Traefik swarm cleanup: global HTTPS redirect, API compression, zero-downtime API deploys, security headers #474

Closed
opened 2026-07-11 05:30:29 +00:00 by spikerj · 0 comments
Owner

Findings from a Traefik 3.7.7 dashboard + stack-file audit.

Problems

  1. Global HTTP→HTTPS redirect is dead. The http-catchall labels on the traefik stack never materialize: traefik.enable is commented out (with exposedbydefault=false), the rule is on http_catchall while entrypoints/middlewares are on http-catchall, and HostRegexp('{any:.+}') is Traefik v2 syntax. Hosts with only websecure routers (ids, postfixadmin, webmail, sonarqube, spam) 404 on plain http.
  2. Every stack hand-rolls the redirect — four+ duplicate redirectscheme middlewares (gitea-redirect, spikersoft-backend-redirect, spikersoft-gameserver-redirect, ome-stream-redirect, test-redirectscheme, draw-redirectscheme) and a -http router per service.
  3. API responses are never compressed: compresstraefik sits on spikersoft-backend-http (the redirect-only port-80 router) while the websecure router carries only the (no-op) redirectscheme middleware. Gitea has the same inversion (compress on the http router only).
  4. Every CI deploy of the API is a brief outage: replicas: 1, no healthcheck, default stop-first update order.
  5. No security headers (HSTS, nosniff, frame-options, referrer-policy) on any public router.
  6. Dead config: unused testHeader middleware, draw-redirectscheme defined but never referenced, drawio references test-redirectscheme without defining it (cross-stack dependency).

Fix

  • Entrypoint-level redirect on webwebsecure (permanent) in the traefik stack; ACME HTTP-01 still answered before the redirect. Remove the broken catchall labels. Add --ping + container healthcheck to traefik itself.
  • Strip all -http routers and redirectscheme middlewares from all 16 service stacks.
  • Backend: gzip-compress + new secure-headers middleware on the websecure router; liveness-only container healthcheck (NOT curl -f /healthz — that endpoint aggregates dependency checks and would restart-loop the API during a dependency outage); update_config: order: start-first for zero-downtime deploys.
  • secure-headers (HSTS 1y, nosniff, SAMEORIGIN, strict referrer) attached to learn/www/api routers.
  • Gitea: move compress to the websecure router.

Decisions

  • Dashboard stays --api.insecure=true on :8081, LAN-only (intranet is trusted; per Joey).
  • serversTransport.insecureSkipVerify=true stays for now — moving to the internal-CA rootCAs serversTransport requires distributing the CA cert to the traefik node first (separate follow-up).
  • InfluxDB metrics token still plaintext in the stack file — separate follow-up to rotate + move to a secret.

Deploy order

  1. traefik stack first (turns on the global redirect; per-stack redirects become redundant but harmless).
  2. Then redeploy the other stacks (any order, but do drawio promptly — its websecure router references test-redirectscheme defined only in other stacks, so it breaks if the defining stacks redeploy first).
Findings from a Traefik 3.7.7 dashboard + stack-file audit. ## Problems 1. **Global HTTP→HTTPS redirect is dead.** The `http-catchall` labels on the traefik stack never materialize: `traefik.enable` is commented out (with `exposedbydefault=false`), the rule is on `http_catchall` while entrypoints/middlewares are on `http-catchall`, and `HostRegexp('{any:.+}')` is Traefik v2 syntax. Hosts with only websecure routers (ids, postfixadmin, webmail, sonarqube, spam) 404 on plain http. 2. **Every stack hand-rolls the redirect** — four+ duplicate `redirectscheme` middlewares (`gitea-redirect`, `spikersoft-backend-redirect`, `spikersoft-gameserver-redirect`, `ome-stream-redirect`, `test-redirectscheme`, `draw-redirectscheme`) and a `-http` router per service. 3. **API responses are never compressed**: `compresstraefik` sits on `spikersoft-backend-http` (the redirect-only port-80 router) while the websecure router carries only the (no-op) redirectscheme middleware. Gitea has the same inversion (compress on the http router only). 4. **Every CI deploy of the API is a brief outage**: replicas: 1, no healthcheck, default stop-first update order. 5. No security headers (HSTS, nosniff, frame-options, referrer-policy) on any public router. 6. Dead config: unused `testHeader` middleware, `draw-redirectscheme` defined but never referenced, drawio references `test-redirectscheme` without defining it (cross-stack dependency). ## Fix - Entrypoint-level redirect on `web` → `websecure` (permanent) in the traefik stack; ACME HTTP-01 still answered before the redirect. Remove the broken catchall labels. Add `--ping` + container healthcheck to traefik itself. - Strip all `-http` routers and redirectscheme middlewares from all 16 service stacks. - Backend: `gzip-compress` + new `secure-headers` middleware on the websecure router; liveness-only container healthcheck (NOT `curl -f /healthz` — that endpoint aggregates dependency checks and would restart-loop the API during a dependency outage); `update_config: order: start-first` for zero-downtime deploys. - `secure-headers` (HSTS 1y, nosniff, SAMEORIGIN, strict referrer) attached to learn/www/api routers. - Gitea: move compress to the websecure router. ## Decisions - Dashboard stays `--api.insecure=true` on :8081, LAN-only (intranet is trusted; per Joey). - `serversTransport.insecureSkipVerify=true` stays for now — moving to the internal-CA `rootCAs` serversTransport requires distributing the CA cert to the traefik node first (separate follow-up). - InfluxDB metrics token still plaintext in the stack file — separate follow-up to rotate + move to a secret. ## Deploy order 1. `traefik` stack first (turns on the global redirect; per-stack redirects become redundant but harmless). 2. Then redeploy the other stacks (any order, but do `drawio` promptly — its websecure router references `test-redirectscheme` defined only in other stacks, so it breaks if the defining stacks redeploy first).
Sign in to join this conversation.