services: traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true networks: - traefik-public ports: - "80:80" - "443:443" environment: - TZ=Europe/Berlin volumes: # Docker socket for service discovery - /var/run/docker.sock:/var/run/docker.sock:ro # Static configuration - ./traefik.yml:/traefik.yml:ro # Dynamic configuration - ./dynamic:/dynamic:ro # SSL certificates - ./acme.json:/acme.json # Logs - ./logs:/logs labels: # Enable Traefik for itself - "traefik.enable=true" # Dashboard - "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.michaelschiemer.de`)" - "traefik.http.routers.traefik-dashboard.entrypoints=websecure" - "traefik.http.routers.traefik-dashboard.tls=true" - "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.traefik-dashboard.service=api@internal" - "traefik.http.routers.traefik-dashboard.middlewares=traefik-auth" # BasicAuth for dashboard (user: admin, password: generate with htpasswd) # htpasswd -nb admin your_password - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$8kj9d7lj$$r.x5jhLVPLuCDLvJ6x0Hd0" # Allow ACME challenges without redirect (higher priority) - "traefik.http.routers.acme-challenge.rule=PathPrefix(`/.well-known/acme-challenge`)" - "traefik.http.routers.acme-challenge.entrypoints=web" - "traefik.http.routers.acme-challenge.priority=200" # Global redirect to HTTPS (lower priority, matches everything else) - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`)" - "traefik.http.routers.http-catchall.entrypoints=web" - "traefik.http.routers.http-catchall.middlewares=redirect-to-https" - "traefik.http.routers.http-catchall.priority=1" - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https" - "traefik.http.middlewares.redirect-to-https.redirectscheme.permanent=true" # Security headers middleware - "traefik.http.middlewares.security-headers.headers.frameDeny=true" - "traefik.http.middlewares.security-headers.headers.contentTypeNosniff=true" - "traefik.http.middlewares.security-headers.headers.browserXssFilter=true" - "traefik.http.middlewares.security-headers.headers.stsSeconds=31536000" - "traefik.http.middlewares.security-headers.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.security-headers.headers.stsPreload=true" # Compression middleware - "traefik.http.middlewares.compression.compress=true" # Rate limiting middleware (100 requests per second) - "traefik.http.middlewares.rate-limit.ratelimit.average=100" - "traefik.http.middlewares.rate-limit.ratelimit.burst=50" healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 30s timeout: 10s retries: 3 start_period: 10s networks: traefik-public: external: true