# Traefik Edge Stack Reverse proxy for everything on this host. The goal: keep Cloudflare in front, expose a private LAN entrypoint, and let Docker stacks self-register through labels without leaking secrets. ## Architecture Snapshot - **Static config (`traefik.yml`)** - EntryPoints: `web/websecure` on `10.0.0.225`, `internal_web/internal_websecure` on `192.168.50.4`. - Trusted IP lists are managed by `scripts/update_cloudflare_ips.py`. - Docker provider is discovery-only; every container opts in with labels. - File provider loads everything in `dynamic.d/`. - **Dynamic config (`dynamic.d/`)** - `middlewares/` – retry, compression, CrowdSec (rendered from template). - `transports/fast-upstreams.yml` – shared connection pool tuning. - `routers/` – internal-only routers (public ones stay in labels). - **Host networking** Traefik runs with `network_mode: host` so it can bind to both IPs simultaneously. Switching to bridge mode would require duplicating Traefik or adding another L4 hop, so host mode stays. ## Secrets Workflow 1. Copy `.env.example` → `.env` and fill: - `CLOUDFLARE_EMAIL`, `CLOUDFLARE_DNS_API_TOKEN` - `CROWDSEC_LAPI_KEY` 2. Render secret-aware dynamic files: ```bash ./scripts/render_dynamic.sh ``` This uses `templates/crowdsec.yml.tmpl` and writes `dynamic.d/middlewares/crowdsec.yml` (ignored by git). ## Runbook ```bash # start / update Traefik docker compose up -d traefik # refresh Cloudflare IPs and restart safely python scripts/update_cloudflare_ips.py # tail logs tail -f traefik.log tail -f access.log ``` Rotate CrowdSec keys? Edit `.env`, rerun `render_dynamic.sh`, then `docker compose up -d traefik`. ## Service Labels Cheat Sheet ```yaml labels: - traefik.enable=true - traefik.http.routers.myapp.rule=Host(`app.example.com`) - traefik.http.routers.myapp.entrypoints=websecure - traefik.http.routers.myapp.tls.certresolver=letsencrypt - traefik.http.routers.myapp.middlewares=crowdsec@file,retry-fast@file,compress-middleware@file - traefik.http.services.myapp.loadbalancer.serversTransport=fast-upstreams@file - traefik.http.services.myapp.loadbalancer.server.port=3000 - traefik.docker.network=traefik_default ``` Most stacks use the same middleware chain: CrowdSec bouncer (plugin), retry, and compression. Internal-only services skip CrowdSec by pointing at the `internal_*` entrypoints. ## Performance Notes - Access logs are buffered with headers trimmed to keep syscalls down. - Compression enforces a 1 KB minimum and respects the client’s preferred encoding. - Shared transport keeps 64 idle connections per backend with aggressive idle/response timeouts. - `retry-fast` retries once after 50 ms, smoothing transient Puma/Node hiccups without hammering backends. ## Things to Remember - Watchtower is still enabled for Traefik; pin the image tag when you need deterministic upgrades. - `scripts/update_cloudflare_ips.py` rewrites the static trusted IP block and restarts Traefik—run it via cron. - Dashboard auth is intentionally disabled because access only happens from the LAN entrypoint. If that changes, re-enable `basicauth`.