Traefik Reverse Proxy 2025: Vollständiger Docker SSL Guide

Traefik v3DockerSSL/TLSProduction-Ready
Lesedauer: 20 Minuten • Schwierigkeit: Fortgeschritten • Datum: 14. März 2025

Traefik ist der moderne Reverse Proxy für Docker-Umgebungen. Automatische Service-Discovery, SSL-Zertifikate per Let's Encrypt, Load Balancing und middleware-basierte Request-Verarbeitung - alles in einem Tool. Dieser Guide zeigt dir den kompletten Setup von Zero bis Production.

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

FeatureTraefikNGINXApache
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
💡 Verification: Das Network sollte Subnet 172.18.0.0/16 oder ähnlich haben

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/
⚠️ Wichtig: acme.json MUSS chmod 600 haben, sonst funktioniert Let's Encrypt nicht!

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: true

Traefik 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: true
💡 Tipp: Verwende zunächst Let's Encrypt Staging für Tests, dann auf Production umstellen

Dynamische 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: 1m

4. 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
💡 Sicherheit: Verwende Zone-spezifische Tokens statt Global API Key

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
⚠️ Häufige Fehler:
• 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: bridge

Load 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 Container

6. 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
          - &quot;admin:$2y$10$X...&quot;
    
    # IP Whitelist
    admin-whitelist:
      ipWhiteList:
        sourceRange:
          - &quot;192.168.1.0/24&quot;
          - &quot;10.0.0.0/16&quot;
    
    # 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:
  - &quot;traefik.http.routers.api.middlewares=api-ratelimit,security-headers&quot;
  - &quot;traefik.http.routers.admin.middlewares=admin-auth,admin-whitelist&quot;

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:
  - &quot;traefik.enable=true&quot;
  - &quot;traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)&quot;
  - &quot;traefik.http.routers.dashboard.entrypoints=websecure&quot;
  - &quot;traefik.http.routers.dashboard.tls=true&quot;
  - &quot;traefik.http.routers.dashboard.tls.certresolver=cloudflare&quot;
  - &quot;traefik.http.routers.dashboard.middlewares=dashboard-auth&quot;
  - &quot;traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$10$$X...&quot;
  - &quot;traefik.http.routers.dashboard.service=api@internal&quot;

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/4475

8. 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