Traefik Docker Guide 2026: The Ultimate Reverse Proxy
Set up Traefik with Docker for automatic SSL, service discovery, and load balancing. Complete guide for modern container deployments.
Traefik Docker Guide: Automatic Reverse Proxy
Traefik is the cloud-native reverse proxy. It discovers your Docker containers and automatically routes traffic to them — with free SSL certificates.
What is Traefik?
Traefik sits in front of your services:
Internet → Traefik → Container A (app.domain.com)
→ Container B (api.domain.com)
→ Container C (admin.domain.com)
Key features:
- Auto-discovery — Detects new containers
- Auto-SSL — Let's Encrypt integration
- Load balancing — Multiple containers per service
- Middleware — Auth, rate limiting, headers
- Dashboard — Visual service overview
Why Traefik vs Nginx?
| Feature | Traefik | Nginx |
|---|---|---|
| Docker integration | Native | Manual config |
| Auto SSL | Built-in | Certbot needed |
| Service discovery | Automatic | Manual |
| Config reload | Hot reload | Requires restart |
| Learning curve | Moderate | Lower |
| Performance | Excellent | Excellent |
Traefik wins for Docker environments. Nginx for static configs.
VPS Requirements
Traefik is lightweight:
- 1 vCPU
- 512MB RAM (for Traefik itself)
- Ports 80, 443
Your VPS specs depend on your services, not Traefik.
Basic Setup
Step 1: Create Network
docker network create traefik-public
Step 2: Create Traefik Config Directory
mkdir -p /opt/traefik
cd /opt/traefik
Step 3: Create Docker Compose
# docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- 80:80
- 443:443
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./acme.json:/acme.json
- ./config:/config:ro
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.yourdomain.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xxxxx"
networks:
traefik-public:
external: true
Step 4: Create Traefik Config
# traefik.yml
api:
dashboard: true
insecure: false
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik-public
file:
directory: /config
watch: true
certificatesResolvers:
letsencrypt:
acme:
email: you@yourdomain.com
storage: /acme.json
httpChallenge:
entryPoint: web
Step 5: Create Certificate Storage
touch acme.json
chmod 600 acme.json
mkdir config
Step 6: Generate Dashboard Password
htpasswd -nb admin your-secure-password
# Output: admin:$apr1$...
# Use this in docker-compose.yml, doubling the $ signs
Step 7: Launch Traefik
docker compose up -d
Access dashboard: https://traefik.yourdomain.com
Adding Services
Example: Nginx
# In a separate docker-compose.yml
version: '3.8'
services:
nginx:
image: nginx:alpine
container_name: nginx
restart: unless-stopped
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.nginx.rule=Host(`www.yourdomain.com`)"
- "traefik.http.routers.nginx.entrypoints=websecure"
- "traefik.http.routers.nginx.tls.certresolver=letsencrypt"
networks:
traefik-public:
external: true
That's it! Traefik discovers the container and:
- Routes
www.yourdomain.comto it - Gets SSL certificate automatically
- Handles HTTPS termination
Example: Node.js App
services:
api:
build: .
container_name: api
networks:
- traefik-public
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.yourdomain.com`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
- "traefik.http.services.api.loadbalancer.server.port=3000"
networks:
traefik-public:
external: true
Note: loadbalancer.server.port specifies the container port.
Middleware
Basic Auth
labels:
- "traefik.http.middlewares.auth.basicauth.users=user:$$hashed$$password"
- "traefik.http.routers.admin.middlewares=auth"
Rate Limiting
labels:
- "traefik.http.middlewares.ratelimit.ratelimit.average=100"
- "traefik.http.middlewares.ratelimit.ratelimit.burst=50"
- "traefik.http.routers.api.middlewares=ratelimit"
IP Whitelist
labels:
- "traefik.http.middlewares.ipwhitelist.ipwhitelist.sourcerange=192.168.1.0/24,10.0.0.0/8"
- "traefik.http.routers.admin.middlewares=ipwhitelist"
Headers
labels:
- "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"
Redirect
labels:
- "traefik.http.middlewares.redirect.redirectregex.regex=^https://old.domain.com/(.*)"
- "traefik.http.middlewares.redirect.redirectregex.replacement=https://new.domain.com/$${1}"
Compress
labels:
- "traefik.http.middlewares.compress.compress=true"
- "traefik.http.routers.web.middlewares=compress"
Multiple Domains
Same Container
labels:
- "traefik.http.routers.web.rule=Host(`domain1.com`) || Host(`domain2.com`)"
With Redirect
labels:
- "traefik.http.routers.www.rule=Host(`www.domain.com`)"
- "traefik.http.routers.www.middlewares=redirect-to-apex"
- "traefik.http.middlewares.redirect-to-apex.redirectregex.regex=^https://www\\.(.+)"
- "traefik.http.middlewares.redirect-to-apex.redirectregex.replacement=https://$${1}"
Load Balancing
Multiple Containers
services:
api:
image: myapi
deploy:
replicas: 3
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.domain.com`)"
Traefik automatically load balances across replicas.
Sticky Sessions
labels:
- "traefik.http.services.api.loadbalancer.sticky.cookie=true"
- "traefik.http.services.api.loadbalancer.sticky.cookie.name=server_id"
Health Checks
labels:
- "traefik.http.services.api.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.api.loadbalancer.healthcheck.interval=10s"
Path-Based Routing
labels:
- "traefik.http.routers.api.rule=Host(`domain.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.web.rule=Host(`domain.com`) && PathPrefix(`/`)"
Strip Path Prefix
labels:
- "traefik.http.middlewares.strip-api.stripprefix.prefixes=/api"
- "traefik.http.routers.api.middlewares=strip-api"
/api/users becomes /users for the backend.
Wildcard Certificates
For *.domain.com:
# traefik.yml
certificatesResolvers:
letsencrypt:
acme:
email: you@domain.com
storage: /acme.json
dnsChallenge:
provider: cloudflare
# docker-compose.yml
environment:
- CF_API_EMAIL=you@domain.com
- CF_API_KEY=your-api-key
Then use:
labels:
- "traefik.http.routers.web.tls.certresolver=letsencrypt"
- "traefik.http.routers.web.tls.domains[0].main=domain.com"
- "traefik.http.routers.web.tls.domains[0].sans=*.domain.com"
File-Based Configuration
For non-Docker services, use file provider:
# /opt/traefik/config/external.yml
http:
routers:
external-service:
rule: "Host(`external.domain.com`)"
service: external-service
tls:
certResolver: letsencrypt
services:
external-service:
loadBalancer:
servers:
- url: "http://192.168.1.100:8080"
Traefik watches the config directory and reloads automatically.
Metrics & Monitoring
Enable Metrics
# traefik.yml
metrics:
prometheus:
entryPoint: metrics
buckets:
- 0.1
- 0.3
- 1.2
- 5.0
entryPoints:
metrics:
address: ":8082"
Grafana Dashboard
Use dashboard ID 11462 for Traefik metrics.
Access Logs
# traefik.yml
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
filters:
statusCodes:
- "400-599"
bufferingSize: 100
Mount the log directory:
volumes:
- ./logs:/var/log/traefik
Troubleshooting
Container Not Discovered
- Check network:
docker network inspect traefik-public
- Verify labels:
docker inspect container_name | grep -A 50 Labels
- Check
traefik.enable=true
SSL Not Working
- Check ACME log:
docker logs traefik 2>&1 | grep -i acme
Verify acme.json permissions (600)
Ensure port 80 is open for HTTP challenge
502 Bad Gateway
- Check container is running
- Verify port is correct in labels
- Check container logs
View Active Configuration
Dashboard shows all routers, services, and middlewares. Or:
curl http://localhost:8080/api/http/routers
Production Checklist
- Dashboard protected with auth
- acme.json has 600 permissions
- Access logs enabled
- Metrics for monitoring
- Health checks configured
- Rate limiting on public APIs
- Security headers middleware
- Proper network isolation
Best VPS for Traefik
Traefik itself is tiny. Size for your services:
| Provider | Plan | Price | Best For |
|---|---|---|---|
| Hetzner | CX21 | €5.39 | 5-10 services |
| Hostinger | KVM1 | $4.99 | Budget setup |
| Vultr | VC2 | $12 | Global reach |
FAQ
Traefik vs Nginx Proxy Manager?
Traefik for Docker-native setups. NPM for simpler GUI-based config.
How many services can Traefik handle?
Hundreds easily. It's designed for microservices at scale.
Is Traefik secure?
Yes. Don't expose the API without auth. Keep updated.
Can I migrate from Nginx?
Yes. Gradual migration is possible — run both temporarily.
Does Traefik support HTTP/3?
Yes, as of v3.0. Enable in entrypoint config.
Summary
Traefik automates what you'd manually configure in Nginx:
| Task | Nginx | Traefik |
|---|---|---|
| Add service | Edit config, reload | Add labels |
| Get SSL | Run certbot | Automatic |
| Load balance | Configure upstream | Automatic |
| Remove service | Edit config, reload | Stop container |
For Docker deployments, Traefik is the modern choice. Set it up once, add services with labels forever.
Ready to get started?
Get the best VPS hosting deal today. Hostinger offers 4GB RAM VPS starting at just $4.99/mo.
Get Hostinger VPS — $4.99/mo// up to 75% off + free domain included
// related topics
fordnox
Expert VPS reviews and hosting guides. We test every provider we recommend.
// last updated: February 8, 2026. Disclosure: This article may contain affiliate links.