Blame
|
1 | # Traefik |
||||||
| 2 | ||||||||
| 3 | ← [[Home]] |
|||||||
| 4 | ||||||||
|
5 | Reverse proxy running in the `network` Swarm stack on PCT 108. Handles all `*.carr-family.org` traffic from the Cloudflare Tunnel. |
||||||
|
6 | |||||||
| 7 | - **Config:** `/mnt/tank/appdata/traefik/traefik.yml` |
|||||||
| 8 | - **Dynamic routes:** `/mnt/tank/appdata/traefik/routes.yml` |
|||||||
| 9 | - **Certs:** `/mnt/tank/appdata/traefik/certs/acme.json` |
|||||||
| 10 | - **TLS:** Cloudflare DNS challenge (`CF_DNS_API_TOKEN_FILE` from Docker secret) |
|||||||
| 11 | - **Entrypoints:** `web` (80 → 443 redirect), `websecure` (443) |
|||||||
| 12 | - **Trusted IPs:** `192.168.2.0/24` (LAN), `100.64.0.0/10` (Tailscale), Cloudflare IP ranges |
|||||||
| 13 | ||||||||
|
14 | Two providers: |
||||||
| 15 | - **Swarm** — local Docker socket on PCT 108 (Swarm service labels) |
|||||||
| 16 | - **Docker** — `tcp://192.168.2.191:2375` for standalone containers on PCT 102 (e.g. Jellyfin) |
|||||||
| 17 | ||||||||
| 18 | External access: Cloudflare Tunnel on the Proxmox host → `https://192.168.2.82:443`. A 504 means the tunnel is up but Traefik (or the backend) is unreachable. |
|||||||
|
19 | |||||||
| 20 | --- |
|||||||
| 21 | ||||||||
| 22 | ## Static Routes (`routes.yml`) |
|||||||
| 23 | ||||||||
|
24 | Used for services not in Docker Swarm. After any edit, force-restart Traefik: |
||||||
| 25 | ```bash |
|||||||
| 26 | pct exec 108 -- docker service update --force network_traefik |
|||||||
| 27 | ``` |
|||||||
|
28 | |||||||
|
29 | | Host | Backend | Notes | |
||||||
| 30 | |------|---------|-------| |
|||||||
| 31 | | `homeassist.carr-family.org` | `192.168.2.129:8123` | Home Assistant VM | |
|||||||
| 32 | | `qbittorrent-vpn.carr-family.org` | `192.168.2.190:8081` | via gluetun | |
|||||||
| 33 | | `qbittorrent.carr-family.org` | `192.168.2.190:8080` | lan-only | |
|||||||
| 34 | | `ai.carr-family.org` | `192.168.2.81:3000` | PCT 107 | |
|||||||
| 35 | | `gcjobs.carr-family.org` | `192.168.2.81:8501` | PCT 107 | |
|||||||
| 36 | | `gcjobs-filler.carr-family.org` | `192.168.2.81:8000` | PCT 107, no Authentik | |
|||||||
| 37 | | `jellyfin.carr-family.org` | `192.168.2.191:8096` | PCT 101 standalone | |
|||||||
| 38 | | `qui.carr-family.org` | `192.168.2.190:7476` | PCT 101 | |
|||||||
| 39 | | `n8n.carr-family.org` | `192.168.2.83:5678` | lan-only | |
|||||||
| 40 | | `litellm.carr-family.org` | `192.168.2.83:4000` | lan-only | |
|||||||
| 41 | | `openclaw.carr-family.org` | `192.168.2.83:18789` | lan-only | |
|||||||
| 42 | | `odysseus.carr-family.org` | `192.168.2.83:7000` | lan-only | |
|||||||
| 43 | | `otterwiki.carr-family.org` | `192.168.2.105:8081` | PCT 104 standalone | |
|||||||
| 44 | | `pterodactyl.carr-family.org` | `192.168.2.136:80` | lan-only | |
|||||||
|
45 | |||||||
| 46 | --- |
|||||||
| 47 | ||||||||
| 48 | ## Middlewares |
|||||||
| 49 | ||||||||
| 50 | | Name | Purpose | |
|||||||
| 51 | |------|---------| |
|||||||
|
52 | | `lan-only` | IP allowlist — LAN (`192.168.2.0/24`) + Tailscale (`100.64.0.0/10`) | |
||||||
| 53 | | `auth` | Basic auth via `traefik_auth` Docker secret | |
|||||||
|
54 | | `secure-headers` | HSTS | |
||||||
|
55 | | `authentik` | ForwardAuth → Authentik outpost (removed from `routes.yml` as of 2026-06-12) | |
||||||
|
56 | |||||||
|
57 | **Cross-provider middleware reference:** Middlewares defined in `routes.yml` (file provider) must be referenced as `authentik@file` / `lan-only@file` in Swarm service `deploy.labels` — plain names default to `@swarm` and return 404. |
||||||
|
58 | |||||||
| 59 | --- |
|||||||
| 60 | ||||||||
| 61 | ## Docker Secrets |
|||||||
| 62 | ||||||||
| 63 | | Secret | Purpose | |
|||||||
| 64 | |--------|---------| |
|||||||
|
65 | | `cf_dns_token` | Cloudflare DNS challenge for wildcard TLS | |
||||||
|
66 | | `cf_api_email` | Cloudflare account email | |
||||||
|
67 | | `traefik_auth` | Dashboard basic auth credentials | |
||||||
|
68 | |||||||
| 69 | --- |
|||||||
| 70 | ||||||||
| 71 | ## routes.yml Edit Gotcha |
|||||||
| 72 | ||||||||
|
73 | `sed -i` creates a new inode; Traefik's bind-mount stays pinned to the old inode and won't see the change. Always write in-place (e.g. `tee` or `python3`) **and** force-restart after any edit: |
||||||
|
74 | |||||||
| 75 | ```bash |
|||||||
| 76 | pct exec 108 -- docker service update --force network_traefik |
|||||||
| 77 | ``` |
|||||||
| 78 | ||||||||
| 79 | --- |
|||||||
| 80 | ||||||||
|
81 | ## Authentik ForwardAuth |
||||||
| 82 | ||||||||
| 83 | The Authentik proxy outpost handles ForwardAuth requests. ForwardAuth address: |
|||||||
| 84 | ``` |
|||||||
| 85 | http://authentik_authentik-proxy:9000/outpost.goauthentik.io/auth/traefik |
|||||||
| 86 | ``` |
|||||||
| 87 | ||||||||
| 88 | The outpost also has its own router (`authentik-outpost`) catching `*.carr-family.org` paths starting with `/outpost.goauthentik.io/` at priority 15, so auth callbacks after login are handled correctly. |
|||||||
| 89 | ||||||||
| 90 | **To protect a Swarm service**, add to its `deploy.labels`: |
|||||||
| 91 | ```yaml |
|||||||
| 92 | - "traefik.http.routers.<name>.middlewares=authentik@file" |
|||||||
| 93 | ``` |
|||||||
| 94 | ||||||||
| 95 | **To protect a static route** in `routes.yml`, add to the router: |
|||||||
| 96 | ```yaml |
|||||||
| 97 | middlewares: |
|||||||
| 98 | - authentik |
|||||||
| 99 | ``` |
|||||||
| 100 | ||||||||
| 101 | > Note (2026-06-12): authentik middleware definition removed from routes.yml. All static routes are currently unprotected. Swarm services with the label still have it but the middleware is not defined, so it has no effect. |
|||||||
| 102 | ||||||||
| 103 | --- |
|||||||
| 104 | ||||||||
| 105 | ## Cloudflare DNS-only (bypasses Traefik entirely) |
|||||||
|
106 | |||||||
|
107 | | Host | IP | Ports | Notes | |
||||||
| 108 | |------|----|-------|-------| |
|||||||
| 109 | | `satisfactory.carr-family.org` | `174.95.181.77` (public IP) | TCP+UDP 7777, TCP 8888 | Grey cloud (proxy off); router port forwards → `192.168.2.134`. TCP 8888 = ReliableMessaging. Ports 15000/15777 obsolete since Patch 1.0. | |
|||||||
