1. Warum Traefik als Reverse Proxy?
Das Problem ohne Reverse Proxy
Stell dir vor: Du betreibst 5 verschiedene Web-Services auf deinem Server. WordPress auf Port 8080, eine API auf 3000, Grafana auf 3001, ein weiteres Tool auf 8090. Deine Nutzer müssen sich alle diese Ports merken und in der URL eingeben. Unprofessionell und nutzerunfreundlich.
❌ https://example.com:8080/wordpress
❌ https://example.com:3000/api
❌ https://example.com:3001/grafana
Die Traefik-Lösung
Traefik löst das elegant: Ein einziger Entry-Point auf Port 80/443, automatische Service-Discovery über Docker Labels, SSL-Zertifikate werden automatisch erstellt und erneuert. Deine Services bekommen saubere Subdomains:
✅ https://blog.example.com
✅ https://api.example.com
✅ https://monitoring.example.com
Traefik vs. NGINX vs. Apache
| Feature | Traefik | NGINX | Apache |
|---|---|---|---|
| Docker Integration | 🔥 Native | ⚡ Manuell | ⚠️ Komplex |
| Automatische SSL | 🔥 Let's Encrypt | ⚡ Certbot | ⚠️ Certbot |
| Service Discovery | 🔥 Automatisch | ⚠️ Config-Files | ⚠️ VirtualHost |
| Load Balancing | 🔥 Built-in | 🔥 Excellent | ⚡ mod_proxy |
| Learning Curve | ⚡ Mittel | ⚠️ Steep | ⚡ Mittel |
💡 Praxis-Beispiel aus 2024
Bei einem Client hatte ich 12 verschiedene Services (WordPress, Grafana, API, Nextcloud, etc.) auf einem VPS laufen. Mit NGINX hätte ich 12 separate Config-Files verwalten müssen, bei jedem neuen Service manuell SSL-Zertifikate einrichten. Mit Traefik: Neuer Service = Docker-Container mit 3 Labels starten. Fertig.
2. Docker-Netzwerk verstehen
Bevor wir Traefik konfigurieren, müssen wir verstehen, wie Docker-Netzwerke funktionieren. Das ist der Schlüssel zu einem robusten Setup.
Das Traefik-Network erstellen
Traefik braucht ein eigenes Docker-Network, über das es mit anderen Containern kommuniziert:
# Traefik-Network erstellen docker network create traefik-network # Network-Details anzeigen docker network inspect traefik-network # Alle Networks anzeigen docker network ls
Verzeichnisstruktur vorbereiten
# Traefik-Verzeichnis erstellen
mkdir -p /opt/traefik/{data,logs}
cd /opt/traefik
# SSL-Zertifikate-File vorbereiten (wichtig!)
touch data/acme.json
chmod 600 data/acme.json
# Log-Files erstellen
touch logs/traefik.log
touch logs/access.log
# Verzeichnisstruktur prüfen
tree /opt/traefik/Docker-Compose Architektur verstehen
In unserer Architektur haben wir zwei Arten von docker-compose.yml Files:
traefik/docker-compose.yml
Startet Traefik selbst. Läuft dauerhaft, verwaltet alle anderen Services.
services/*/docker-compose.yml
Individuelle Services mit Traefik-Labels. Werden automatisch entdeckt.
3. Traefik Installation & Konfiguration
Traefik v3 Docker-Compose
Hier ist die komplette docker-compose.yml für Traefik. Jede Zeile ist erklärt:
# /opt/traefik/docker-compose.yml
version: '3.8'
services:
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
# Ports für HTTP und HTTPS
ports:
- "80:80" # HTTP
- "443:443" # HTTPS
- "8080:8080" # Dashboard (nur lokal!)
# Netzwerk-Konfiguration
networks:
- traefik-network
# Volumes für Konfiguration und SSL-Zertifikate
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./data/traefik.yml:/traefik.yml:ro
- ./data/acme.json:/acme.json
- ./logs:/var/log/traefik
# Environment-Variablen für Let's Encrypt
environment:
- CF_API_EMAIL=your-email@example.com
- CF_API_KEY=your-cloudflare-api-key
# Labels für Traefik-Dashboard
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=cloudflare"
- "traefik.http.services.dashboard.loadbalancer.server.port=8080"
# Dashboard Authentifizierung (htpasswd)
- "traefik.http.routers.dashboard.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."
networks:
traefik-network:
external: trueTraefik Konfigurationsdatei
Die traefik.yml ist das Herzstück der Konfiguration:
# /opt/traefik/data/traefik.yml
global:
checkNewVersion: false
sendAnonymousUsage: false
# Entry Points - wo Traefik Traffic empfängt
entryPoints:
web:
address: ":80"
# HTTP zu HTTPS Redirect
http:
redirections:
entryPoint:
to: websecure
scheme: https
permanent: true
websecure:
address: ":443"
# HSTS Header für Sicherheit
http:
middlewares:
- default-headers@file
tls:
options: default
# Docker Provider - Service Discovery
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false
network: traefik-network
# File Provider für statische Konfiguration
file:
filename: /dynamic.yml
watch: true
# SSL/TLS Konfiguration
certificatesResolvers:
cloudflare:
acme:
tlsChallenge: {}
email: your-email@example.com
storage: acme.json
# Let's Encrypt Production Server
# caServer: https://acme-v02.api.letsencrypt.org/directory
# DNS Challenge für Wildcard-Zertifikate
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
# API und Dashboard
api:
dashboard: true
debug: true
# Logging
log:
level: INFO
filePath: "/var/log/traefik/traefik.log"
format: json
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
# Metrics für Monitoring
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: trueDynamische Konfiguration für Middlewares
# /opt/traefik/data/dynamic.yml
tls:
options:
default:
sslStrategies:
- "tls.SniStrict"
minVersion: "VersionTLS12"
cipherSuites:
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
- "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
http:
middlewares:
# Sicherheits-Headers für alle Services
default-headers:
headers:
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
customFrameOptionsValue: SAMEORIGIN
customRequestHeaders:
X-Forwarded-Proto: https
# Cloudflare Real-IP
real-ip:
ipWhiteList:
sourceRange:
- "103.21.244.0/22"
- "103.22.200.0/22"
- "103.31.4.0/22"
# ... weitere Cloudflare IPs
# Rate Limiting
rate-limit:
rateLimit:
average: 100
burst: 50
period: 1m4. SSL-Zertifikate mit Let's Encrypt
DNS-Challenge vs HTTP-Challenge
Let's Encrypt bietet verschiedene Methoden zur Domain-Validierung:
DNS Challenge (Empfohlen)
- ✅ Wildcard-Zertifikate möglich
- ✅ Funktioniert auch für interne Services
- ✅ Keine Port 80 Exposition nötig
- ⚠️ Benötigt DNS-Provider API
HTTP Challenge
- ✅ Keine API-Keys nötig
- ✅ Funktioniert mit jedem Provider
- ⚠️ Port 80 muss öffentlich erreichbar sein
- ❌ Keine Wildcard-Zertifikate
Cloudflare DNS-Challenge Setup
Für Cloudflare brauchst du einen API-Token mit Zone:Read und Zone:Zone:Edit Rechten:
# 1. Cloudflare API-Token erstellen # https://dash.cloudflare.com/profile/api-tokens # Template: "Custom token" # Permissions: # - Zone:Zone:Read # - Zone:Zone:Edit # Zone Resources: # - Include:Specific zone:example.com # 2. Environment-Variablen setzen export CF_API_EMAIL="your-email@example.com" export CF_API_KEY="your-global-api-key" # ODER für API-Token: export CF_DNS_API_TOKEN="your-zone-specific-token" # 3. In docker-compose.yml eintragen environment: - CF_API_EMAIL=your-email@example.com - CF_DNS_API_TOKEN=your-api-token
Wildcard-Zertifikate konfigurieren
# Wildcard-Zertifikat für *.example.com
certificatesResolvers:
cloudflare:
acme:
email: your-email@example.com
storage: acme.json
dnsChallenge:
provider: cloudflare
resolvers:
- "1.1.1.1:53"
- "1.0.0.1:53"
delayBeforeCheck: 30
# In Service-Labels verwenden:
labels:
- "traefik.http.routers.myapp.tls=true"
- "traefik.http.routers.myapp.tls.certresolver=cloudflare"
- "traefik.http.routers.myapp.tls.domains[0].main=example.com"
- "traefik.http.routers.myapp.tls.domains[0].sans=*.example.com"SSL-Probleme debuggen
# Let's Encrypt Status prüfen docker exec traefik cat /acme.json | jq . # SSL-Zertifikat Details anzeigen openssl s_client -connect example.com:443 -servername example.com \ -showcerts </dev/null | openssl x509 -noout -text # Traefik Logs für SSL-Fehler docker logs traefik 2>&1 | grep -i "acme\|certificate\|tls" # DNS-Propagation prüfen dig TXT _acme-challenge.example.com @8.8.8.8
• acme.json hat falsche Permissions (muss 600 sein)
• DNS-Provider API-Limits erreicht
• Let's Encrypt Rate-Limits (5 Zertifikate/Stunde/Domain)
5. Service Labels & Routing
WordPress mit Traefik Labels
# WordPress mit Traefik - docker-compose.yml
version: '3.8'
services:
wordpress:
image: wordpress:latest
container_name: wordpress-blog
restart: unless-stopped
volumes:
- ./wordpress:/var/www/html
- ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini
environment:
WORDPRESS_DB_HOST: mariadb
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: secure_password
WORDPRESS_DB_NAME: wordpress
networks:
- traefik-network
- wordpress-network
labels:
# Traefik aktivieren
- "traefik.enable=true"
# Docker-Network definieren
- "traefik.docker.network=traefik-network"
# HTTP Router (wird zu HTTPS umgeleitet)
- "traefik.http.routers.wordpress-http.rule=Host(`blog.example.com`)"
- "traefik.http.routers.wordpress-http.entrypoints=web"
# HTTPS Router
- "traefik.http.routers.wordpress.rule=Host(`blog.example.com`)"
- "traefik.http.routers.wordpress.entrypoints=websecure"
- "traefik.http.routers.wordpress.tls=true"
- "traefik.http.routers.wordpress.tls.certresolver=cloudflare"
# Load Balancer (Port des Services)
- "traefik.http.services.wordpress.loadbalancer.server.port=80"
# Middlewares anwenden
- "traefik.http.routers.wordpress.middlewares=default-headers,compress"
mariadb:
image: mariadb:10.11
container_name: wordpress-db
restart: unless-stopped
environment:
MYSQL_ROOT_PASSWORD: super_secure_root_password
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: secure_password
volumes:
- ./mariadb:/var/lib/mysql
networks:
- wordpress-network
networks:
traefik-network:
external: true
wordpress-network:
driver: bridgeLoad Balancing mit mehreren Containern
# docker-compose.yml für Load Balancing
version: '3.8'
services:
api-1:
image: my-api:latest
container_name: api-instance-1
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.services.api.loadbalancer.server.port=3000"
api-2:
image: my-api:latest
container_name: api-instance-2
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.services.api.loadbalancer.server.port=3000"
api-3:
image: my-api:latest
container_name: api-instance-3
networks:
- traefik-network
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.example.com`)"
- "traefik.http.services.api.loadbalancer.server.port=3000"
# Load Balancer Algorithmus konfigurieren
- "traefik.http.services.api.loadbalancer.sticky=true"
- "traefik.http.services.api.loadbalancer.sticky.cookie.name=api-server"
networks:
traefik-network:
external: true
# Health Checks für automatisches Failover
# In der Anwendung /health Endpoint implementieren
# Traefik prüft automatisch und entfernt defekte Container6. Middleware für erweiterte Features
Authentication & Security Middleware
# Rate Limiting & Security Middlewares in dynamic.yml
http:
middlewares:
# Rate Limiting
api-ratelimit:
rateLimit:
average: 100 # 100 Requests pro Minute
burst: 50 # Burst von 50 erlaubt
period: 1m
# BasicAuth für Admin-Bereiche
admin-auth:
basicAuth:
users:
# htpasswd -n admin
- "admin:$2y$10$X..."
# IP Whitelist
admin-whitelist:
ipWhiteList:
sourceRange:
- "192.168.1.0/24"
- "10.0.0.0/16"
# Security Headers
security-headers:
headers:
sslRedirect: true
forceSTSHeader: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 31536000
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
customRequestHeaders:
X-Forwarded-Proto: https
# Middleware in Service Labels verwenden:
labels:
- "traefik.http.routers.api.middlewares=api-ratelimit,security-headers"
- "traefik.http.routers.admin.middlewares=admin-auth,admin-whitelist"7. Dashboard und Monitoring
Traefik Dashboard sichern
# Dashboard-Passwort generieren htpasswd -n admin # Output: admin:$2y$10$X... (für Labels verwenden) # Traefik Container Labels für Dashboard labels: - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)" - "traefik.http.routers.dashboard.entrypoints=websecure" - "traefik.http.routers.dashboard.tls=true" - "traefik.http.routers.dashboard.tls.certresolver=cloudflare" - "traefik.http.routers.dashboard.middlewares=dashboard-auth" - "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$10$$X..." - "traefik.http.routers.dashboard.service=api@internal"
Prometheus Metrics
# traefik.yml - Metrics aktivieren
metrics:
prometheus:
addEntryPointsLabels: true
addServicesLabels: true
addRoutersLabels: true
# Grafana Dashboard für Traefik-Metriken
# Dashboard ID: 4475 (Traefik 2.0 Dashboard)
# Importieren über: https://grafana.com/grafana/dashboards/44758. Troubleshooting & Production Tips
Häufige Probleme & Lösungen
❌ Problem: Service nicht erreichbar (404)
# Debug-Commands:
docker network inspect traefik-network
docker logs traefik | grep ERROR
curl -H "Host: yourapp.com" http://localhost:80/Häufige Ursachen: Container nicht im richtigen Network, falsche Port-Config, traefik.enable=true vergessen
⚠️ Problem: SSL-Zertifikat wird nicht erstellt
# SSL Debug:
docker exec traefik cat /acme.json | jq .
dig TXT _acme-challenge.example.com @8.8.8.8
docker logs traefik | grep -i "acme\|certificate"Lösungen: acme.json Permissions prüfen (600), DNS-Propagation warten, Let's Encrypt Rate-Limits beachten
Production Best Practices
✅ Security Checklist
- • Dashboard nie public zugänglich
- • HSTS Header aktiviert
- • Rate Limiting für APIs
- • Security Headers gesetzt
- • Backup der acme.json
⚡ Performance Tips
- • HTTP/2 aktivieren
- • Gzip/Brotli Compression
- • Browser Caching Headers
- • Health Checks für Load Balancer
- • Metrics für Monitoring
🎯 Fazit: Traefik in Production
Mit diesem Setup hast du einen production-ready Traefik Reverse Proxy, der automatische SSL-Zertifikate, Load Balancing, Security Middleware und umfassendes Monitoring bietet. Der größte Vorteil: Neue Services werden automatisch entdeckt und sind sofort über HTTPS erreichbar.
📊 Typische Verbesserungen nach Traefik-Implementierung:
• SSL-Setup: 2 Stunden → 2 Minuten (automatisch)
• Neue Services online: 30 Minuten → 30 Sekunden
• Load Balancer Config: 1 Tag → 5 Minuten
• SSL-Renewal: manuell → vollautomatisch
• Downtime für Updates: 15 Min → 0 Sekunden