Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
# Ignore key files for decrypting credentials and more.
/config/*.key

# Ignore Traefik certificate storage
acme.json


/app/assets/builds/*
!/app/assets/builds/.keep
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,40 @@ bin/dev

## Docker

### One-command deploy
### Production with SSL

Use Docker Compose with Traefik for HTTPS. Create a `.env` file with SSL and app config:

**Let's Encrypt (wildcard):**

```bash
# .env
DOMAIN=uptime.example.com
WILDCARD_DOMAIN=*.example.com
DNS_PROVIDER=cloudflare
CF_DNS_API_TOKEN=your-token
LETSENCRYPT_EMAIL=you@example.com
# App config (see table above)
ADMIN_EMAILS=admin@example.com,manager@example.com

docker compose up -d
```

**Cloudflare SSL (no cert management):**

```bash
# .env
DOMAIN=uptime.example.com
ENTRYPOINT=web
# App config (see table above)
ADMIN_EMAILS=admin@example.com

docker compose up -d
```

If `ENTRYPOINT` is not set, Traefik defaults to `websecure` (HTTPS) with automatic Let's Encrypt DNS challenge. [Supported DNS providers](https://doc.traefik.io/traefik/https/acme/#dnschallenge)

### One-command deploy (local)

```bash
docker run -d -p 3000:80 \
Expand Down
20 changes: 20 additions & 0 deletions config/traefik/dynamic.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Dynamic configuration
http:
routers:
uptimer:
rule: 'Host(`{{ env "DOMAIN" }}`)'
entryPoints:
- '{{ env "ENTRYPOINT" "websecure" }}'
service: uptimer
tls:
certResolver: letsencrypt
domains:
- main: '{{ env "DOMAIN" }}'
sans:
- '{{ env "WILDCARD_DOMAIN" }}'

services:
uptimer:
loadBalancer:
servers:
- url: "http://up-timer:80"
33 changes: 33 additions & 0 deletions config/traefik/traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Static configuration
global:
sendAnonymousUsage: false

api:
dashboard: false

entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"

providers:
file:
filename: /etc/traefik/dynamic.yml
watch: true

certificatesResolvers:
letsencrypt:
acme:
email: '{{ env "LETSENCRYPT_EMAIL" }}'
storage: /letsencrypt/acme.json
dnsChallenge:
provider: '{{ env "DNS_PROVIDER" "cloudflare" }}'
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
29 changes: 27 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,32 @@
services:
traefik:
image: traefik:v3
container_name: traefik
ports:
- "80:80"
- "443:443"
volumes:
- ./config/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./config/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
- traefik-certs:/letsencrypt
environment:
- ENTRYPOINT=${ENTRYPOINT:-websecure}
- DNS_PROVIDER=${DNS_PROVIDER:-cloudflare}
- CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL}
- DOMAIN=${DOMAIN}
- WILDCARD_DOMAIN=${WILDCARD_DOMAIN}
restart: unless-stopped

up-timer:
image: binilsn/up-timer:latest
build: .
ports:
- "3000:80"
environment:
- RAILS_ENV=production
- RAILS_MASTER_KEY=${RAILS_MASTER_KEY}
- ADMIN_EMAILS=${ADMIN_EMAILS}
- SOLID_QUEUE_IN_PUMA=true
- APP_HOST=${DOMAIN}
volumes:
- up-timer-storage:/rails/storage
- up-timer-db:/rails/db
Expand All @@ -17,7 +35,14 @@ services:
interval: 10s
timeout: 3s
retries: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.uptimer.rule=Host(`${DOMAIN}`)"
- "traefik.http.routers.uptimer.entrypoints=websecure"
- "traefik.http.routers.uptimer.tls.certresolver=letsencrypt"
restart: unless-stopped

volumes:
up-timer-storage:
up-timer-db:
traefik-certs:
Loading