Refs #1 ## Security * Remove the CrowdSec LAPI key from config.yml. Traefik does not interpolate env vars in its YAML config, so the key had to be literal there - which is why the file kept drifting out of version control. It is now defined as a docker-compose label, where compose substitutes ${CROWDSEC_LAPI_KEY} from .env. config.yml is therefore secret-free and stays in git. NOTE: this renames the middleware crowdsec-bouncer@file -> @docker. Site stacks referencing @file must be updated. The old key remains in this repo's history and must still be rotated and scrubbed - removing it here does not un-expose it. * Move the dashboard basic-auth hash out of docker-compose.yml into .env. In .env every '$' must be doubled to '$$', or compose silently collapses the hash to an empty string and the dashboard rejects every password. * Stop publishing port 8080. The API is not insecure-mode, so nothing served there; publishing it only widened exposure. ## Geoblock (the availability fix) * allowUnknownCountries: false -> true. Previously a geojs.io outage made every lookup "unknown" and therefore blocked, taking sites down for US visitors too - a third-party service in the critical path with no degraded mode. Now an outage degrades to "geoblocking ineffective". CrowdSec still blocks actual attackers. * cacheSize: 25 -> 5000. At 25, nearly every visitor triggered a fresh API call, adding up to 750ms and risking rate limits. ## Dev host support * Add traefik.dev.yml, selected by TRAEFIK_STATIC_CONFIG in .env (defaults to traefik.yml, so prod behaviour is unchanged). It differs from traefik.yml ONLY in the ACME challenge type: public port 80 forwards to prod for its renewals, so an HTTP-01 challenge for a dev hostname hits prod's Traefik, matches no router, and 404s. Dev uses DNS-01 via Route 53 instead, which needs no inbound connectivity. * Add .env.example documenting every variable. ## Captured from prod's working tree Prod had uncommitted drift; these were running but never committed: plugin bumps (bouncer v1.3.3->v1.3.5, geoblock v0.2.7->v0.2.8), the entryPoints HTTP->HTTPS redirect with priority 1, and httpClientTimeout: 0. The priority: 1 on that redirect is load-bearing - it keeps the redirect below normal routers so basil's Host(`localhost`) HTTP route still serves. Do not raise it. ## Verified on dev (prkl10), Traefik 3.7.10 7 routers / 8 middlewares, 0 warnings, 0 errors. Certificates issued via DNS-01. pihole and technitium routers preserved. Sites serving 200.
31 lines
1.4 KiB
Plaintext
31 lines
1.4 KiB
Plaintext
# Copy to .env and fill in. .env is gitignored.
|
|
|
|
# Hostname for the Traefik dashboard. Must resolve publicly for the
|
|
# Let's Encrypt HTTP-01 challenge to succeed, even though the router itself
|
|
# is additionally restricted to the LAN by internal-whitelist@file.
|
|
# dev: traefik-dev.pkartchner.com
|
|
# prod: traefik.pkartchner.com
|
|
TRAEFIK_DASHBOARD_HOST=traefik-dev.pkartchner.com
|
|
|
|
# Basic-auth users for the dashboard, htpasswd format.
|
|
#
|
|
# EVERY '$' MUST BE DOUBLED to '$$'. Compose interpolates the substituted value,
|
|
# so a single '$' makes it read "$apr1" as an unset variable and silently
|
|
# collapse the hash to an empty string — which produces a dashboard that
|
|
# rejects every password rather than an obvious error.
|
|
#
|
|
# Generate and escape in one step:
|
|
# htpasswd -nb admin 'yourpassword' | sed -e 's/\$/\$\$/g'
|
|
TRAEFIK_DASHBOARD_AUTH=admin:$$apr1$$CHANGEME$$REPLACETHISVALUE
|
|
|
|
# CrowdSec bouncer API key. Generate after the crowdsec stack is up:
|
|
# docker exec crowdsec cscli bouncers add traefik-bouncer -o raw
|
|
# Consumed by the crowdsec-bouncer middleware defined as a Docker label in
|
|
# docker-compose.yml, so it never appears in any committed file.
|
|
CROWDSEC_LAPI_KEY=
|
|
|
|
# Static config file for THIS host.
|
|
# prod: leave unset (defaults to ./traefik.yml, HTTP-01)
|
|
# dev : ./traefik.dev.yml (DNS-01, because public port 80 forwards to prod)
|
|
# TRAEFIK_STATIC_CONFIG=./traefik.dev.yml
|