# Traefik static configuration — DEFAULT / PRODUCTION. # # Selected by TRAEFIK_STATIC_CONFIG in .env (defaults to this file). # The dev host uses traefik.dev.yml, which differs ONLY in the ACME challenge # type, because public port 80 forwards to prod so HTTP-01 cannot work there. # # NOTE: Traefik does NOT interpolate environment variables in this file. Any # secret must be a docker-compose label instead, where compose substitutes it # from .env. That is why the CrowdSec bouncer is defined in docker-compose.yml. api: dashboard: true debug: false experimental: plugins: bouncer: moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin version: v1.3.5 geoblock: moduleName: github.com/PascalMinder/geoblock version: v0.2.8 entryPoints: http: address: ":80" http: redirections: entryPoint: to: https scheme: https permanent: true # priority 1 keeps this redirect BELOW normal routers, which default # to a priority derived from rule length. That is what allows basil's # Host(`localhost`) HTTP router to keep serving without redirecting. # Do not raise this value. priority: 1 https: address: ":443" # Backends here use self-signed certs (harbor, etc). This disables verification # of upstream TLS for ALL services — matches prod, but it is a real weakening. # Prefer per-service serversTransport if you ever narrow this. serversTransport: insecureSkipVerify: true providers: docker: endpoint: "unix:///var/run/docker.sock" exposedByDefault: false network: traefik httpClientTimeout: 0 file: filename: /config.yml watch: true certificatesResolvers: letsencrypt: acme: email: pkartch@gmail.com storage: acme.json # DNS-01 via Route 53 (since 2026-11-03; was HTTP-01). Proves control with # an _acme-challenge TXT record, so certificates no longer depend on public # port 80 reaching this host, and a name can be certified before its A # record points here (e.g. a site migration). Credentials: IAM user # traefik-prod-dns01 in .env, allowed ONLY to write _acme-challenge.* TXT # records in the pkartchner.com and backyardhoneycomb.com zones. dnsChallenge: provider: route53 # Check propagation against public resolvers: Pi-hole answers for # internal names and never sees the TXT record. resolvers: - "1.1.1.1:53" - "8.8.8.8:53" log: level: INFO accessLog: filePath: "/var/log/traefik/access.log"