Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy. It integrates with your existing infrastructure (Docker, Swarm, Kubernetes, Consul, …) and configures itself automatically and dynamically - routers, services, and TLS certs appear from container labels or watched config files, no restarts.
This is my working v3 setup, plus recipes for the things you always end up needing: wildcard certs, proxying non-Docker services, Basic Auth, and Google SSO.
Base setup
docker-compose.yaml
name: traefik-localhost
services:
traefik:
image: traefik:3
container_name: traefik.localhost
restart: always
mem_limit: 256M
volumes:
- ./:/opt/traefik
- ./:/etc/traefik
network_mode: host
labels:
- com.centurylinklabs.watchtower.enable=truetraefik.yaml (static config)
# Traefik v3.x main configuration - /opt/traefik/traefik.yaml
# Listen on http/https; force http → https.
entryPoints:
https:
address: ':443'
http:
address: ':80'
http:
redirections:
entryPoint:
to: https
scheme: https
ssh:
address: ':2222'
monitoring:
address: ':9100'
# Let's Encrypt - HTTP challenge (see recipe 1 for the DNS/wildcard variant)
certificatesResolvers:
lets-encrypt:
acme:
email: noreply@example.com
storage: /opt/traefik/acme/acme.json
httpChallenge:
entryPoint: http
metrics:
prometheus:
addServicesLabels: true
addEntryPointsLabels: true
entryPoint: monitoring
accessLog:
filePath: /dev/stdout
providers:
file:
directory: /opt/traefik/conf.d
watch: true
docker:
exposedByDefault: false
endpoint: "tcp://localhost:2375"
watch: trueconf.d/00-common.yaml (secure TLS defaults)
tls:
options:
default:
minVersion: VersionTLS12
cipherSuites:
- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
- TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
- TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256The
fileprovider watchesconf.d/- drop a.yamlin and Traefik hot-reloads it. Everything below is aconf.d/*.yamlfragment (or a static-config / compose edit where noted).
Recipe 1 - Cloudflare DNS challenge (wildcard certs)
The HTTP challenge can’t issue wildcard certificates and needs port 80 reachable from the internet. The DNS challenge solves both - it proves domain ownership via a Cloudflare DNS record.
In traefik.yaml, replace the resolver’s httpChallenge with:
certificatesResolvers:
lets-encrypt:
acme:
email: noreply@example.com
storage: /opt/traefik/acme/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"In docker-compose.yaml, give Traefik a scoped Cloudflare API token
(create it in Cloudflare → My Profile → API Tokens with Zone → DNS → Edit):
environment:
- CF_DNS_API_TOKEN=your-cloudflare-api-tokenThen request a wildcard on any router’s TLS block:
tls:
certResolver: lets-encrypt
domains:
- main: "example.com"
sans:
- "*.example.com"Recipe 2 - Reverse proxy to an external (non-Docker) service
For a box Traefik can’t auto-discover (a NAS, a VM, a device on the LAN), declare
it with the file provider. conf.d/10-external.yaml:
http:
routers:
nas:
rule: "Host(`nas.example.com`)"
entryPoints:
- https
service: nas
tls:
certResolver: lets-encrypt
services:
nas:
loadBalancer:
servers:
- url: "http://192.168.1.50:8080" # the real backendAdd more url: lines under servers: and Traefik load-balances across them.
Recipe 3 - Basic Auth
A quick password gate (e.g. for a dashboard). Generate a hash with
htpasswd -nB admin (from apache2-utils). conf.d/20-auth.yaml:
http:
middlewares:
basic-auth:
basicAuth:
users:
- "admin:$apr1$xxxxxxxx$yyyyyyyyyyyyyyyyyyyyy."Gotcha: in a file (like this), paste the hash as-is. In a docker label, every
$must be doubled to$$or compose will try to expand it.
Attach it to any router:
http:
routers:
dashboard:
rule: "Host(`traefik.example.com`)"
entryPoints: [https]
service: api@internal
middlewares:
- basic-auth
tls:
certResolver: lets-encryptRecipe 4 - Google SSO via traefik-forward-auth
For real SSO (login with Google, allowlist emails), front your services with
traefik-forward-auth. It’s a
tiny auth service Traefik consults on every request via a forwardAuth middleware.
1. Google OAuth client - in Google Cloud Console → APIs & Services →
Credentials, create an OAuth 2.0 Client ID (Web application) with the
authorized redirect URI: https://auth.example.com/_oauth.
2. Add the service to docker-compose.yaml:
traefik-forward-auth:
image: thomseddon/traefik-forward-auth:2
container_name: traefik-forward-auth.localhost
restart: always
ports:
- "4181:4181" # host-networked Traefik reaches it on localhost
environment:
- DEFAULT_PROVIDER=google
- PROVIDERS_GOOGLE_CLIENT_ID=your-id.apps.googleusercontent.com
- PROVIDERS_GOOGLE_CLIENT_SECRET=your-secret
- SECRET=change-me-to-a-random-string # signs the auth cookie
- AUTH_HOST=auth.example.com
- COOKIE_DOMAIN=example.com
- WHITELIST=you@gmail.com # allowed emails (comma-separated)3. Define the middleware in conf.d/30-forward-auth.yaml:
http:
middlewares:
google-auth:
forwardAuth:
address: "http://localhost:4181" # Traefik uses host networking here
authResponseHeaders:
- X-Forwarded-User
trustForwardHeader: true4. Protect any router by adding the middleware:
middlewares:
- google-authNow hitting that host bounces you through Google login; only allowlisted emails
get in, and the authenticated user arrives in the X-Forwarded-User header.