Introduction
Traefik shines where Nginx struggles: environments where services come and go (containers, K8s). Each new Docker container is auto-discovered via labels and exposed in HTTPS.
Features:
- Auto-discovery (Docker, K8s, Consul, etcd, file)
- Automatic HTTPS via Let's Encrypt
- Load balancing
- Real-time web dashboard
- Rich middlewares (auth, rate limit, headers, CORS)
- HTTP/2, HTTP/3, gRPC
- Prometheus metrics
Prerequisites
- Linux VPS with Docker + Docker Compose
- Domain pointing to VPS
- Ports 80, 443 open
- Root access
Step 1: Base structure
sudo mkdir -p /opt/traefik/{config,letsencrypt}
cd /opt/traefik
sudo touch letsencrypt/acme.json
sudo chmod 600 letsencrypt/acme.json
Step 2: Static config
sudo nano /opt/traefik/config/traefik.yml
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
http:
tls:
certResolver: letsencrypt
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: web
providers:
docker:
exposedByDefault: false
network: traefik
log:
level: INFO
accessLog: {}
Step 3: docker-compose.yml
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
networks:
- traefik
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./config/traefik.yml:/traefik.yml:ro
- ./letsencrypt:/letsencrypt
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.your-domain.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$abc..."
networks:
traefik:
external: true
sudo docker network create traefik
echo $(htpasswd -nbB admin YOUR_PASSWORD) | sed -e s/\\$/\\$\\$/g
Step 4: Start
cd /opt/traefik
sudo docker compose up -d
sudo docker compose logs -f
Access dashboard: https://traefik.your-domain.com.
Step 5: Expose app via labels
services:
myapp:
image: nginx
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.myapp.rule=Host(`myapp.your-domain.com`)"
- "traefik.http.routers.myapp.entrypoints=websecure"
- "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
- "traefik.http.services.myapp.loadbalancer.server.port=80"
networks:
traefik:
external: true
docker compose up -d
Step 6: Useful middlewares
Basic auth
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$abc..."
- "traefik.http.routers.myapp.middlewares=auth"
Rate limit
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.ratelimit.ratelimit.burst=200"
- "traefik.http.routers.myapp.middlewares=ratelimit"
Compression
- "traefik.http.middlewares.compress.compress=true"
- "traefik.http.routers.myapp.middlewares=compress"
Security headers
- "traefik.http.middlewares.security.headers.stsSeconds=31536000"
- "traefik.http.middlewares.security.headers.stsIncludeSubdomains=true"
- "traefik.http.middlewares.security.headers.contentTypeNosniff=true"
- "traefik.http.middlewares.security.headers.framedeny=true"
- "traefik.http.routers.myapp.middlewares=security"
Chain multiple
- "traefik.http.routers.myapp.middlewares=auth,ratelimit,compress,security"
Step 7: Whoami for testing
services:
whoami:
image: traefik/whoami
networks:
- traefik
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.your-domain.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=letsencrypt"
Step 8: Wildcard with DNS-01
certificatesResolvers:
letsencrypt:
acme:
email: [email protected]
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
In docker-compose:
environment:
- [email protected]
- CF_API_KEY=your_cloudflare_global_api_key
- "traefik.http.routers.myapp.tls.domains[0].main=your-domain.com"
- "traefik.http.routers.myapp.tls.domains[0].sans=*.your-domain.com"
Step 9: Advanced routing
# Path prefix
- "traefik.http.routers.api.rule=Host(`api.your-domain.com`) && PathPrefix(`/v1`)"
# Multiple hosts
- "traefik.http.routers.myapp.rule=Host(`a.com`) || Host(`b.com`)"
# Strip prefix
- "traefik.http.middlewares.strip.stripprefix.prefixes=/api"
- "traefik.http.routers.myapp.middlewares=strip"
Step 10: Sticky sessions
- "traefik.http.services.myapp.loadbalancer.sticky.cookie.name=session"
- "traefik.http.services.myapp.loadbalancer.sticky.cookie.secure=true"
Step 11: Prometheus metrics
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
Step 12: Healthcheck
- "traefik.http.services.myapp.loadbalancer.healthcheck.path=/healthz"
- "traefik.http.services.myapp.loadbalancer.healthcheck.interval=10s"
- "traefik.http.services.myapp.loadbalancer.healthcheck.timeout=3s"
Troubleshooting
Service not discovered
Check traefik.enable=true, network traefik, rule syntax.
sudo docker logs traefik | grep myapp
Cert won't generate
sudo cat /opt/traefik/letsencrypt/acme.json
If empty: check Traefik logs, DNS, ports 80/443.
404 Page not found
curl -v https://myapp.your-domain.com
Host header must match rule exactly.
Dashboard inaccessible
Check auth middleware and api@internal service reference.
Useful commands
docker exec traefik traefik healthcheck
docker compose logs -f traefik
cat /opt/traefik/letsencrypt/acme.json | jq '.letsencrypt.Certificates[].domain.main'
docker compose up -d # auto-reload on label change
docker compose pull && docker compose up -d
Conclusion
Traefik is ideal for:
- Dynamic Docker environments
- Kubernetes stacks
- Frequently changing configs
- Multi-tenancy
For static prod, Nginx or Caddy are more direct. But once containers come into play, Traefik changes the game.
Going further:
- Enable Traefik Pilot for advanced observability
- Use Crowdsec bouncer for collaborative security
- Combine with Authelia for SSO/MFA
Resources
- Official docs: https://doc.traefik.io/traefik/
- Tutorials: https://doc.traefik.io/traefik/getting-started/quick-start/
- Docker image: https://hub.docker.com/_/traefik
- GitHub: https://github.com/traefik/traefik

















