Traditionele aanpak met Nginx:
# nginx.conf - handmatige configuratie voor elke service
upstream backend1 {
server 192.168.1.10:3000;
server 192.168.1.11:3000;
}
upstream backend2 {
server 192.168.1.20:4000;
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend1;
}
}
server {
listen 80;
server_name admin.example.com;
location / {
proxy_pass http://backend2;
}
}
Problemen:
Wat is Traefik?
Voordelen van Traefik:
Traefik ontdekt services via verschillende providers:
# traefik.yml
providers:
docker:
exposedByDefault: false # Alleen services met labels exposen
kubernetes: {}
file:
directory: /etc/traefik/dynamic
watch: true
Poorten waarop Traefik luistert:
entryPoints:
web:
address: ":80" # HTTP verkeer
websecure:
address: ":443" # HTTPS verkeer
admin:
address: ":8080" # Dashboard
Definiëren welk verkeer naar welke service gaat:
# Via Docker labels
labels:
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.routers.webapp.entrypoints=websecure"
Backend servers die het verkeer afhandelen:
labels:
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
Verwerking van requests voor ze naar de backend gaan:
labels:
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."
- "traefik.http.routers.webapp.middlewares=auth"
graph LR
A[Client Request] --> B[Entrypoint :80/:443]
B --> C[Router Matching]
C --> D[Middleware Processing]
D --> E[Service/Backend]
E --> F[Container/Pod]
Directory structuur:
traefik-setup/
├── docker-compose.yml
├── traefik.yml
├── acme.json # SSL certificaten storage
└── apps/
├── webapp1/
│ └── docker-compose.yml
└── webapp2/
└── docker-compose.yml
Traefik hoofdconfiguratie (traefik.yml):
# Global configuratie
global:
checkNewVersion: false
sendAnonymousUsage: false
# API en Dashboard (alleen voor development!)
api:
dashboard: true
insecure: true # ⚠️ Alleen voor development
# Entrypoints
entryPoints:
web:
address: ":80"
# Automatisch redirect naar HTTPS
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
# SSL Certificaten met Let's Encrypt
certificatesResolvers:
letsencrypt:
acme:
email: jouw-email@example.com
storage: /certificates/acme.json
httpChallenge:
entryPoint: web
# Voor testing met staging certificaten
letsencrypt-staging:
acme:
email: jouw-email@example.com
storage: /certificates/acme-staging.json
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"
httpChallenge:
entryPoint: web
# Providers
providers:
docker:
exposedByDefault: false # Veiliger: alleen expliciet gemarkeerde services
network: traefik-public # Netwerk voor Traefik communicatie
file:
directory: /etc/traefik/dynamic
watch: true
# Security: TLS configuratie
tls:
options:
default:
minVersion: "VersionTLS12"
cipherSuites:
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
Main docker-compose.yml:
version: '3.8'
services:
traefik:
image: traefik:v3.0
container_name: traefik
restart: unless-stopped
# Poorten
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Dashboard (alleen development)
# Volumes
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./certificates:/certificates
- /var/run/docker.sock:/var/run/docker.sock:ro # Docker API toegang
# Netwerk
networks:
- traefik-public
# Environment variabelen (indien nodig voor DNS challenge)
environment:
- CF_DNS_API_TOKEN=${CLOUDFLARE_API_TOKEN} # Voor Cloudflare DNS
# Labels voor dashboard
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.localhost`)"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
networks:
traefik-public:
external: true
Voorbeeld: Web applicatie (apps/webapp1/docker-compose.yml):
version: '3.8'
services:
webapp:
image: nginx:alpine
container_name: webapp1
restart: unless-stopped
# Traefik labels voor automatische configuratie
labels:
# Enable Traefik
- "traefik.enable=true"
# HTTP Router (wordt automatisch geredirect naar HTTPS)
- "traefik.http.routers.webapp1-http.rule=Host(`webapp1.example.com`)"
- "traefik.http.routers.webapp1-http.entrypoints=web"
# HTTPS Router
- "traefik.http.routers.webapp1.rule=Host(`webapp1.example.com`)"
- "traefik.http.routers.webapp1.entrypoints=websecure"
- "traefik.http.routers.webapp1.tls=true"
- "traefik.http.routers.webapp1.tls.certresolver=letsencrypt"
# Service configuratie
- "traefik.http.services.webapp1.loadbalancer.server.port=80"
# Middleware toevoegen
- "traefik.http.middlewares.webapp1-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.routers.webapp1.middlewares=webapp1-headers"
# Volume voor content
volumes:
- ./html:/usr/share/nginx/html:ro
# Netwerk
networks:
- traefik-public
networks:
traefik-public:
external: true
API Backend met database (apps/api/docker-compose.yml):
version: '3.8'
services:
api:
image: node:18-alpine
container_name: api-backend
restart: unless-stopped
working_dir: /app
command: npm start
# Environment
environment:
- NODE_ENV=production
- DATABASE_URL=mongodb://database:27017/myapp
# Volumes
volumes:
- ./src:/app
# Traefik labels
labels:
- "traefik.enable=true"
# API routes
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.routers.api.entrypoints=websecure"
- "traefik.http.routers.api.tls=true"
- "traefik.http.routers.api.tls.certresolver=letsencrypt"
# Service configuratie
- "traefik.http.services.api.loadbalancer.server.port=3000"
# CORS middleware
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,POST,PUT,DELETE,OPTIONS"
- "traefik.http.middlewares.api-cors.headers.accesscontrolalloworigin=*"
- "traefik.http.middlewares.api-cors.headers.accesscontrolmaxage=86400"
- "traefik.http.routers.api.middlewares=api-cors"
# Netwerken
networks:
- traefik-public
- backend
# Dependencies
depends_on:
- database
database:
image: mongo:6
container_name: api-database
restart: unless-stopped
# Data persistence
volumes:
- mongodb_data:/data/db
# Alleen backend netwerk (niet publiek toegankelijk)
networks:
- backend
volumes:
mongodb_data:
networks:
traefik-public:
external: true
backend:
internal: true # Alleen interne communicatie
Round-robin met health checks:
services:
webapp-1:
image: myapp:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
- "traefik.http.services.webapp.loadbalancer.healthcheck.path=/health"
- "traefik.http.services.webapp.loadbalancer.healthcheck.interval=30s"
networks:
- traefik-public
webapp-2:
image: myapp:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.webapp.rule=Host(`app.example.com`)"
- "traefik.http.services.webapp.loadbalancer.server.port=3000"
networks:
- traefik-public
Verschillende services op hetzelfde domein:
# Frontend app
labels:
- "traefik.http.routers.frontend.rule=Host(`example.com`) && PathPrefix(`/`)"
- "traefik.http.routers.frontend.priority=1" # Lagere prioriteit
# API service
labels:
- "traefik.http.routers.api.rule=Host(`example.com`) && PathPrefix(`/api`)"
- "traefik.http.routers.api.priority=10" # Hogere prioriteit
- "traefik.http.middlewares.api-stripprefix.stripprefix.prefixes=/api"
- "traefik.http.routers.api.middlewares=api-stripprefix"
# Admin panel
labels:
- "traefik.http.routers.admin.rule=Host(`example.com`) && PathPrefix(`/admin`)"
- "traefik.http.routers.admin.priority=5"
Authentication middleware:
# Basic Auth
labels:
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$hash..."
- "traefik.http.routers.admin.middlewares=auth"
# Rate limiting
labels:
- "traefik.http.middlewares.ratelimit.ratelimit.burst=10"
- "traefik.http.middlewares.ratelimit.ratelimit.average=5"
- "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"
Custom headers middleware:
labels:
# Security headers
- "traefik.http.middlewares.security-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
- "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Content-Type-Options=nosniff"
- "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-Frame-Options=DENY"
- "traefik.http.middlewares.security-headers.headers.customresponseheaders.X-XSS-Protection=1; mode=block"
- "traefik.http.middlewares.security-headers.headers.customresponseheaders.Strict-Transport-Security=max-age=31536000; includeSubDomains"
# Toepassen op router
- "traefik.http.routers.webapp.middlewares=security-headers"
Automatische certificaten met HTTP challenge:
# traefik.yml
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /certificates/acme.json
httpChallenge:
entryPoint: web # Port 80 moet publiek toegankelijk zijn
# Docker service labels
labels:
- "traefik.http.routers.webapp.tls.certresolver=letsencrypt"
- "traefik.http.routers.webapp.tls.domains[0].main=example.com"
- "traefik.http.routers.webapp.tls.domains[0].sans=www.example.com,api.example.com"
Cloudflare DNS challenge:
# traefik.yml
certificatesResolvers:
cloudflare:
acme:
email: admin@example.com
storage: /certificates/acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "8.8.8.8:53"
# docker-compose.yml
environment:
- CF_DNS_API_TOKEN=your-cloudflare-api-token
# Service labels voor wildcard certificaat
labels:
- "traefik.http.routers.webapp.tls.certresolver=cloudflare"
- "traefik.http.routers.webapp.tls.domains[0].main=example.com"
- "traefik.http.routers.webapp.tls.domains[0].sans=*.example.com"
Eigen certificaten gebruiken:
# traefik.yml
tls:
stores:
default:
defaultCertificate:
certFile: /certificates/cert.pem
keyFile: /certificates/key.pem
# Of per domein
tls:
certificates:
- certFile: /certificates/example.com.crt
keyFile: /certificates/example.com.key
stores:
- default
Dashboard toegang:
# Lokaal development
http://localhost:8080
# Productie met authenticatie
labels:
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
API endpoints:
# Service status
curl http://localhost:8080/api/http/services
# Routers configuratie
curl http://localhost:8080/api/http/routers
# Middleware configuratie
curl http://localhost:8080/api/http/middlewares
# Health check
curl http://localhost:8080/ping
Uitgebreide logging configuratie:
# traefik.yml
log:
level: INFO # DEBUG, INFO, WARN, ERROR
format: json
filePath: /var/log/traefik/traefik.log
accessLog:
format: json
filePath: /var/log/traefik/access.log
filters:
statusCodes: ["400-499", "500-599"] # Alleen errors loggen
fields:
headers:
defaultMode: keep
names:
User-Agent: redact # Sensitieve data verbergen
Docker logging:
# docker-compose.yml
services:
traefik:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
Veelvoorkomende problemen:
docker logs traefik 2>&1 | grep “service-name”
docker exec traefik ping service-container-name
docker inspect container-name | jq ‘.[0].Config.Labels’
2. **SSL certificaat problemen:**
```bash
# Check certificaat status
curl -I https://example.com
# Let's Encrypt logs
docker logs traefik 2>&1 | grep -i acme
# Certificaat details
openssl s_client -connect example.com:443 -servername example.com
curl -H “Host: example.com” http://localhost/
curl http://localhost:8080/api/http/routers | jq ‘.[] | {name: .name, rule: .rule, priority: .priority}’
## Productie Deployment
### Security Best Practices
**1. Dashboard beveiliging:**
```yaml
# Productie: dashboard uitschakelen of beveiligen
api:
dashboard: true
insecure: false # Dashboard alleen via HTTPS
# Met authenticatie
labels:
- "traefik.http.routers.dashboard.rule=Host(`traefik.internal.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."
2. Netwerk isolatie:
# Gescheiden netwerken
networks:
traefik-public:
external: true
backend:
internal: true # Geen internet toegang
database:
internal: true # Database isolatie
3. Resource limits:
# docker-compose.yml
services:
traefik:
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
Multiple Traefik instances:
# traefik-cluster/docker-compose.yml
version: '3.8'
services:
traefik-1:
image: traefik:v3.0
hostname: traefik-1
deploy:
placement:
constraints: [node.role == manager]
volumes:
- traefik-ssl:/certificates
ports:
- target: 80
published: 80
mode: host
- target: 443
published: 443
mode: host
networks:
- traefik-public
traefik-2:
image: traefik:v3.0
hostname: traefik-2
deploy:
placement:
constraints: [node.role == worker]
volumes:
- traefik-ssl:/certificates
networks:
- traefik-public
volumes:
traefik-ssl:
driver: nfs # Shared storage voor certificaten
networks:
traefik-public:
driver: overlay
attachable: true
Certificaten backup:
#!/bin/bash
# backup-certs.sh
# Backup acme.json
cp /certificates/acme.json /backup/acme.json.$(date +%Y%m%d)
# Sync naar remote storage
rsync -av /backup/ backup-server:/backups/traefik/
# Cleanup oude backups (30 dagen)
find /backup -name "acme.json.*" -mtime +30 -delete
Configuratie backup:
#!/bin/bash
# backup-config.sh
# Docker compose files
tar -czf /backup/traefik-config-$(date +%Y%m%d).tar.gz \
/opt/traefik/docker-compose.yml \
/opt/traefik/traefik.yml \
/opt/traefik/dynamic/
| Feature | Traefik | Nginx |
|---|---|---|
| Auto-discovery | ✅ Automatisch | ❌ Handmatig |
| Dynamic config | ✅ Real-time | ❌ Reload nodig |
| SSL automation | ✅ Let’s Encrypt | ⚠️ Externe tools |
| Dashboard | ✅ Built-in | ❌ Externe tools |
| Performance | ⚠️ Goed | ✅ Excellent |
| Learning curve | ✅ Makkelijk | ⚠️ Complex |
| Feature | Traefik | HAProxy |
|---|---|---|
| Cloud-native | ✅ Yes | ⚠️ Needs tools |
| Load balancing | ✅ Good | ✅ Excellent |
| SSL termination | ✅ Excellent | ✅ Good |
| Configuration | ✅ Labels/annotations | ❌ Config files |
| Monitoring | ✅ Built-in | ⚠️ External |
| Feature | Traefik | Envoy |
|---|---|---|
| Ease of use | ✅ Simple | ❌ Complex |
| Service mesh | ⚠️ Basic | ✅ Advanced |
| Performance | ✅ Good | ✅ Excellent |
| Observability | ✅ Good | ✅ Excellent |
| Configuration | ✅ Declarative | ⚠️ Complex |
Doel: Traefik opzetten met een eenvoudige web applicatie
Stappen:
Verwachte bestanden in /traefik-examples/config-minimal/:
Doel: Meerdere services achter Traefik met verschillende domeinen
Resultaat:
app.localhostapi.localhostadmin.localhostBestanden in /traefik-examples/config-with-labels/:
Doel: Production-ready configuratie met beveiliging
Features:
Bestanden in /traefik-examples/config-all-in-dc/:
Traefik biedt een moderne, cloud-native oplossing voor reverse proxy en load balancing met:
Belangrijkste voordelen:
Wanneer Traefik gebruiken:
Wanneer alternatieven overwegen:
Traefik democratiseert reverse proxy configuratie door complexiteit weg te nemen en best practices automatisch toe te passen, waardoor development teams zich kunnen focussen op hun applicatie logica in plaats van infrastructuur beheer.
Referenties: