🇩🇪 Deutsch | 🇬🇧 English | 🇫🇷 Français
Produktions-fertiger Traefik v3.6 Stack mit Security Best Practices, Let's Encrypt, HTTP/3, Geo-Blocking und umfangreichen Middlewares.
- Features
- Schnellstart - Neuer Server
- Verfügbare Middlewares
- Label-Kombinationen
- Komplette Label-Beispiele
- Projekt-Typen
- Troubleshooting
- Erweiterte Konfiguration
- ✅ TLS 1.3 Only - Maximale Verschlüsselung
- ✅ Security Headers - HSTS, X-Frame-Options, CSP, etc.
- ✅ Geo-Blocking - Blockiert 23 Hochrisiko-Länder
- ✅ Rate Limiting - DoS-Schutz (100 req/s)
- ✅ In-Flight Limiting - Max 100 gleichzeitige Connections
- ✅ BasicAuth - Für Dashboard & Metrics
- ✅ Let's Encrypt - Automatische SSL-Zertifikate
- ✅ HTTP/3 Support - QUIC Protocol
- ✅ Gzip/Brotli Compression - ~70% kleinere Responses
- ✅ Log Rotation - 7 Tage, 5 Backups, 50MB max
- ✅ Dashboard - Web-UI für Traefik
- ✅ Prometheus Metrics -
/metricsEndpoint - ✅ JSON Logs - Strukturiertes Logging
- ✅ Access Logs - Nur Fehler (4xx/5xx), weniger Disk I/O
- ✅ Mailcow Support - ACME Challenge Router für Let's Encrypt
- ✅ Ping Endpoint - Health Check via
/ping
# Docker & Docker Compose installiert?
docker --version
docker compose version
# Ports frei?
sudo netstat -tulpn | grep -E ':80|:443'
# Sollte leer sein oder nur Traefik zeigencd /opt # oder dein bevorzugter Pfad
git clone https://github.com/csaeum/DockerStackTraefik.git
cd DockerStackTraefik# .env erstellen
cp .env.example .env
# .env bearbeiten
nano .envWichtige Variablen:
COMPOSE_PROJECT_NAME=traefik
HOSTRULE=Host(`traefik.deine-domain.de`)
[email protected]
PROXY_NETWORK=traefik_proxy_network
RESTART=unless-stopped
TIMEZONE=Europe/Berlindocker network create traefik_proxy_network# Verzeichnisse erstellen
mkdir -p logs volumes
# Richtige Permissions
chmod 700 volumes
chmod 755 logsdocker compose up -d# Container läuft?
docker compose ps
# Logs checken
docker compose logs -f traefik
# Dashboard erreichbar?
curl -I https://traefik.deine-domain.de/dashboard/
# Erwartung: HTTP/2 401 (Auth required)
# HTTP → HTTPS Redirect?
curl -I http://traefik.deine-domain.de
# Erwartung: 301 Moved Permanently- URL:
https://traefik.deine-domain.de/dashboard/ - User:
traefik-admin - Password: Siehe Passwort ändern unten!
Alle Middlewares sind in configs/traefik-dynamic.yaml definiert und können per @file referenziert werden.
| Middleware | Funktion | Verwendung |
|---|---|---|
redirect-to-https@file |
HTTP → HTTPS Weiterleitung | PFLICHT für HTTP-Router |
redirect-to-www@file |
Redirect auf www-Subdomain | Optional für Websites |
Beispiel:
# Im HTTP-Router
middlewares=redirect-to-https@file
# Im HTTPS-Router (optional)
middlewares=redirect-to-www@file,...| Middleware | Funktion | Konfiguration |
|---|---|---|
security-headers@file |
Security Headers setzen | HSTS (1 Jahr), X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy, Permissions-Policy |
geo-block@file |
Geo-Blocking | Blockiert: RU, CN, IR, IN, PK, BD, ID, SG, PH, VN, TH, MY, KR, KZ, HK, TW, AE, QA, SA, JP, NP, LK |
dashboard-auth@file |
BasicAuth | User: traefik-admin (nur für Traefik) |
Beispiel:
middlewares=security-headers@file,geo-block@fileSecurity Headers im Detail:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()| Middleware | Funktion | Limits |
|---|---|---|
rate-limit@file |
Request Rate Limiting | Average: 100 req/s, Burst: 50, Period: 1s |
in-flight-limit@file |
Concurrent Request Limiting | Max: 100 gleichzeitige Requests pro IP |
Beispiel:
# Für APIs und Login-Seiten
middlewares=rate-limit@file,in-flight-limit@fileWann welches verwenden?
rate-limit@file- Immer empfohlen für Login-Formulare, APIsin-flight-limit@file- Nur bei sehr hoher Last oder DoS-Angriffen
| Middleware | Funktion | Details |
|---|---|---|
compression@file |
Gzip/Brotli Kompression | Encodings: gzip, br, zstd. Min: 1024 bytes. Excludes: text/event-stream |
Beispiel:
middlewares=compression@filePerformance-Gewinn:
- HTML/CSS/JS: ~70% kleiner
- JSON APIs: ~60% kleiner
- Bilder: Keine Kompression (bereits komprimiert)
| Option | Funktion | Details |
|---|---|---|
modern@file |
TLS 1.3 Only | Cipher Suites: AES-128-GCM, AES-256-GCM, ChaCha20-Poly1305, SNI Strict |
Beispiel:
- traefik.http.routers.mein-projekt.tls.options=modern@fileUse Case: Minimale Konfiguration, nur HTTP → HTTPS
# HTTP Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.rule=${HOSTRULE}
- traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.entrypoints=web-http
- traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https@file
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.rule=${HOSTRULE}
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.entrypoints=websecure-https
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.certresolver=letsEncryptErgebnis: HTTP wird zu HTTPS umgeleitet, Let's Encrypt Zertifikat
Use Case: Erzwinge www-Subdomain für Website
# HTTP Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https@file
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=redirect-to-www@fileBeispiel-Flow:
http://example.com→https://example.com(redirect-to-https)https://example.com→https://www.example.com(redirect-to-www)
Wichtig: ${HOSTRULE} muss beide Domains matchen:
HOSTRULE=Host(`example.com`) || Host(`www.example.com`)Use Case: Basis-Sicherheit für alle Projekte
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=security-headers@file,compression@file
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.options=modern@fileErgebnis:
- HSTS Header (1 Jahr)
- X-Frame-Options: DENY
- TLS 1.3 only
- Gzip/Brotli Kompression
Use Case: Öffentliche Website mit geografischem Schutz
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=geo-block@file,security-headers@fileErgebnis: Besucher aus RU, CN, IR, etc. erhalten 403 Forbidden
Use Case: Shopware, WooCommerce, produktive Websites
# HTTP Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}-http.middlewares=redirect-to-https@file
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=redirect-to-www@file,geo-block@file,security-headers@file,compression@file,rate-limit@file
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.options=modern@fileMiddleware-Chain Reihenfolge:
redirect-to-www@file- Domain normalisierengeo-block@file- Länder blockensecurity-headers@file- Security Headerscompression@file- Performancerate-limit@file- DoS-Schutz
Ergebnis: Maximaler Schutz + Performance
Use Case: REST API, GraphQL API
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=security-headers@file,compression@file,rate-limit@file,in-flight-limit@file
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.options=modern@fileKein Geo-Blocking - APIs müssen global erreichbar sein Doppelter DoS-Schutz - Rate Limiting + In-Flight Limiting
Use Case: JTL, Matomo, Adminer, phpMyAdmin
# HTTPS Router
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.middlewares=geo-block@file,security-headers@file,compression@file,rate-limit@file
- traefik.http.routers.${COMPOSE_PROJECT_NAME}.tls.options=modern@fileKein WWW-Redirect - Tools laufen auf Subdomains Mit Geo-Blocking - Zusätzlicher Schutz für Login-Seiten
services:
shopware:
image: shopware/production:latest
container_name: shopware
environment:
APP_URL: https://www.shop.example.com
networks:
- traefik_proxy_network
labels:
# Traefik aktivieren
- traefik.enable=true
# HTTP Router (Port 80 -> HTTPS Redirect)
- traefik.http.routers.shopware-http.rule=Host(`shop.example.com`) || Host(`www.shop.example.com`)
- traefik.http.routers.shopware-http.entrypoints=web-http
- traefik.http.routers.shopware-http.middlewares=redirect-to-https@file
# HTTPS Router (Port 443)
- traefik.http.routers.shopware.rule=Host(`shop.example.com`) || Host(`www.shop.example.com`)
- traefik.http.routers.shopware.entrypoints=websecure-https
- traefik.http.routers.shopware.tls.certresolver=letsEncrypt
- traefik.http.routers.shopware.tls.options=modern@file
- traefik.http.routers.shopware.middlewares=redirect-to-www@file,geo-block@file,security-headers@file,compression@file,rate-limit@file
# Service (Backend Port)
- traefik.http.services.shopware.loadbalancer.server.port=8000
networks:
traefik_proxy_network:
external: trueWas passiert:
- HTTP Request → HTTPS Redirect
- HTTPS Request ohne www → www Redirect
- Geo-Blocking prüft IP
- Security Headers werden gesetzt
- Response wird komprimiert
- Rate Limiting aktiv
- Let's Encrypt Zertifikat
- TLS 1.3 only
services:
jtl:
image: jtl/wawi:latest
container_name: jtl-wawi
networks:
- traefik_proxy_network
labels:
- traefik.enable=true
# HTTP Router
- traefik.http.routers.jtl-http.rule=Host(`jtl.example.com`)
- traefik.http.routers.jtl-http.entrypoints=web-http
- traefik.http.routers.jtl-http.middlewares=redirect-to-https@file
# HTTPS Router
- traefik.http.routers.jtl.rule=Host(`jtl.example.com`)
- traefik.http.routers.jtl.entrypoints=websecure-https
- traefik.http.routers.jtl.tls.certresolver=letsEncrypt
- traefik.http.routers.jtl.tls.options=modern@file
- traefik.http.routers.jtl.middlewares=geo-block@file,security-headers@file,compression@file,rate-limit@file
# Service
- traefik.http.services.jtl.loadbalancer.passHostHeader=true
- traefik.http.services.jtl.loadbalancer.server.port=8080
networks:
traefik_proxy_network:
external: trueUnterschiede zu Shopware:
- Kein WWW-Redirect (läuft auf Subdomain)
passHostHeader=true(wichtig für Reverse Proxy)
services:
api:
image: my-api:latest
container_name: my-api
networks:
- traefik_proxy_network
labels:
- traefik.enable=true
# HTTP Router
- traefik.http.routers.api-http.rule=Host(`api.example.com`)
- traefik.http.routers.api-http.entrypoints=web-http
- traefik.http.routers.api-http.middlewares=redirect-to-https@file
# HTTPS Router
- traefik.http.routers.api.rule=Host(`api.example.com`)
- traefik.http.routers.api.entrypoints=websecure-https
- traefik.http.routers.api.tls.certresolver=letsEncrypt
- traefik.http.routers.api.tls.options=modern@file
- traefik.http.routers.api.middlewares=security-headers@file,compression@file,rate-limit@file,in-flight-limit@file
# Service
- traefik.http.services.api.loadbalancer.server.port=3000
networks:
traefik_proxy_network:
external: trueUnterschiede:
- KEIN Geo-Blocking (global erreichbar)
- Doppelter DoS-Schutz (rate-limit + in-flight-limit)
services:
wordpress:
image: wordpress:latest
container_name: wordpress-staging
networks:
- traefik_proxy_network
labels:
- traefik.enable=true
# HTTP Router
- traefik.http.routers.staging-http.rule=Host(`staging.example.com`)
- traefik.http.routers.staging-http.entrypoints=web-http
- traefik.http.routers.staging-http.middlewares=redirect-to-https@file
# HTTPS Router (Minimale Security für Staging)
- traefik.http.routers.staging.rule=Host(`staging.example.com`)
- traefik.http.routers.staging.entrypoints=websecure-https
- traefik.http.routers.staging.tls.certresolver=letsEncrypt
- traefik.http.routers.staging.tls.options=modern@file
- traefik.http.routers.staging.middlewares=security-headers@file,compression@file
# Service
- traefik.http.services.staging.loadbalancer.server.port=80
networks:
traefik_proxy_network:
external: trueStaging-Besonderheiten:
- Minimale Middlewares (nur essentials)
- Kein Geo-Blocking
- Kein Rate-Limiting (für Tests)
✅ ACME Challenge Integration ist bereits vorkonfiguriert!
Dieser Stack enthält einen speziellen Router mailcow-acme-challenge, der es Mailcow ermöglicht, Let's Encrypt Zertifikate über Traefik zu erhalten.
Die vorkonfigurierten Domains befinden sich in configs/traefik-dynamic.yaml Zeile 134:
# Passe diese Domains an deine Mailcow-Installation an:
mailcow-acme-challenge:
rule: "(Host(`autodiscover.deine-domain.de`) || Host(`autoconfig.deine-domain.de`) || Host(`mail.deine-domain.de`)) && PathPrefix(`/.well-known/acme-challenge/`)"# Mailcow zum Traefik-Netzwerk hinzufügen
docker network connect traefik_proxy_network mailcow-nginx-mailcow-1In Mailcow docker-compose.yaml Labels hinzufügen:
labels:
- traefik.enable=true
- traefik.http.routers.mailcow.rule=Host(`mail.example.com`)
- traefik.http.routers.mailcow.entrypoints=websecure-https
- traefik.http.routers.mailcow.tls.certresolver=letsEncrypt
- traefik.http.services.mailcow.loadbalancer.server.port=443
- traefik.http.services.mailcow.loadbalancer.server.scheme=httpsHinweis: Der ACME Challenge Router hat Priority 1000 und wird automatisch vor anderen Routen verarbeitet.
Charakteristik: Öffentlich, hoher Traffic, Security wichtig
Middlewares:
redirect-to-www@file,geo-block@file,security-headers@file,compression@file,rate-limit@fileProjekte: Shopware, WooCommerce, Magento, PrestaShop
Charakteristik: Interne Tools, Login erforderlich, sensible Daten
Middlewares:
geo-block@file,security-headers@file,compression@file,rate-limit@fileProjekte: JTL, Matomo, Adminer, phpMyAdmin, Portainer
Charakteristik: Global erreichbar, hoher Traffic, DoS-Gefahr
Middlewares:
security-headers@file,compression@file,rate-limit@file,in-flight-limit@fileProjekte: REST API, GraphQL API, Webhooks
Charakteristik: Test-Umgebung, keine Production-Daten
Middlewares:
security-headers@file,compression@fileProjekte: Alle Staging/Dev-Environments
Symptom: curl https://traefik.deine-domain.de/dashboard/ → Timeout
Checks:
# Container läuft?
docker compose ps
# Labels gesetzt?
docker inspect traefik | grep -A 30 Labels
# Logs prüfen
docker compose logs traefik | grep -i errorLösung: Siehe DEPLOYMENT.md
Symptom: HTTP bleibt auf HTTP
Ursache: HTTP-Router fehlt in deinem Projekt
Lösung:
# Diesen Router hinzufügen:
- traefik.http.routers.PROJEKT-http.rule=${HOSTRULE}
- traefik.http.routers.PROJEKT-http.entrypoints=web-http
- traefik.http.routers.PROJEKT-http.middlewares=redirect-to-https@fileSymptom: Kein Zertifikat nach 5 Minuten
Checks:
# ACME Logs
docker compose logs traefik | grep -i acme
# Port 80/443 erreichbar?
curl -I http://deine-domain.deHäufige Ursachen:
- Domain zeigt nicht auf Server
- Port 80/443 durch Firewall blockiert
- Rate-Limit erreicht (5 Certs/Woche pro Domain)
Temporäre Lösung (Staging):
# In traefik.yaml:
caServer: "https://acme-staging-v02.api.letsencrypt.org/directory"Symptom: Legitime User werden geblockt
Lösung: Länder-Liste anpassen in configs/traefik-dynamic.yaml:
geo-block:
plugin:
geoblock:
countries:
- RU # Entfernen oder auskommentieren
# - CN # Auskommentiert = erlaubtNeu starten:
docker compose restart traefikSymptom: 429 Too Many Requests bei normalem Traffic
Lösung: Limits erhöhen in configs/traefik-dynamic.yaml:
rate-limit:
rateLimit:
average: 200 # War: 100
burst: 100 # War: 50
period: 1sJetzt über .env steuerbar! Siehe ENV-CONFIGURATION.md für Details.
Schnell-Anleitung:
# 1. Hash generieren
docker run --rm httpd:alpine htpasswd -nbB traefik-admin "DEIN_NEUES_PASSWORT"
# Output: traefik-admin:$apr1$xyz$abc
# 2. In .env eintragen ($ als $$ escapen!)
# DASHBOARD_PASSWORD_HASH=$$apr1$$xyz$$abc
nano .env
# 3. Container neu erstellen
docker compose up -d --force-recreateWichtig: $ muss als $$ escaped werden!
Beispiel: IP-Whitelist für Admin-Bereich
In configs/traefik-dynamic.yaml hinzufügen:
http:
middlewares:
admin-whitelist:
ipAllowList:
sourceRange:
- "1.2.3.4/32" # Deine IP
- "192.168.1.0/24" # Dein NetzwerkVerwenden:
labels:
- traefik.http.routers.admin.middlewares=admin-whitelist@file,security-headers@file# In traefik-dynamic.yaml
http:
middlewares:
custom-errors:
errors:
status:
- "400-599"
service: error-pages
query: "/{status}.html"
services:
error-pages:
loadBalancer:
servers:
- url: "http://error-pages-container:8080"# In traefik-dynamic.yaml
http:
middlewares:
cors-headers:
headers:
accessControlAllowMethods:
- GET
- POST
- PUT
accessControlAllowOriginList:
- https://example.com
accessControlMaxAge: 100
addVaryHeader: trueVerwenden für API:
- traefik.http.routers.api.middlewares=cors-headers@file,security-headers@file| Datei | Beschreibung |
|---|---|
README.md |
Diese Datei - Komplette Übersicht |
ENV-CONFIGURATION.md |
⭐ .env Steuerung - Passwort, Rate-Limits, etc. |
LABELS-CHECKLIST.md |
Label-Templates & Migration |
DEPLOYMENT.md |
Deployment-Anleitung & Troubleshooting |
CHANGELOG.md |
Alle Änderungen im Detail |
.env.example |
Template für Umgebungsvariablen |
Vor Production-Deployment:
- Dashboard-Passwort geändert
-
.envNICHT in Git -
volumes/Traefik.jsonhat Permissions 600 - Security Headers in allen Projekten
- TLS 1.3 aktiv (prüfen mit SSL Labs)
- Geo-Blocking nach Bedarf anpassen
- Rate-Limiting getestet
- Backups für
volumes/Traefik.jsoneingerichtet - Logs rotieren (automatisch aktiviert)
- URL:
https://traefik.deine-domain.de/dashboard/ - Zeigt: Router, Services, Middlewares, TLS-Certs
- URL:
https://traefik.deine-domain.de/metrics - Format: Prometheus Text-Format
- Metriken: Requests, Duration, Status Codes
- Application:
/logs/traefik.log - Access:
/logs/traefik-access.log(nur 4xx/5xx) - Rotation: 7 Tage, 5 Backups, 50MB max
Sehr alte Browser funktionieren NICHT:
- Internet Explorer 11
- Android < 10
- iOS < 12.2
Kompromiss: TLS 1.2 erlauben (in traefik-dynamic.yaml ändern)
/var/run/docker.sock ist exponiert = Sicherheitsrisiko
Empfehlung: Docker Socket Proxy (TODO)
- 5 Zertifikate pro Woche pro Domain
- 50 Zertifikate pro Woche pro Account
- Bei Tests: Staging CA verwenden!
- Issues: GitHub Issues
- Logs prüfen:
docker compose logs traefik - Debug Mode: In
traefik.yamlsetzen:level: DEBUG
Dieses Projekt ist unter der GNU General Public License v3.0 lizenziert.
Made with ❤️ by WSC - Web SEO Consulting
Dieses Projekt ist kostenlos und Open Source. Wenn es dir geholfen hat, freue ich mich über deine Unterstützung:
Basierend auf:
Contributions sind willkommen! Bitte erstelle einen Pull Request oder öffne ein Issue.
Version: 2025-12-28 | Traefik: v3.6 | TLS: 1.3 Only
© 2025 WSC - Web SEO Consulting. Alle Rechte vorbehalten.