services: traefik: image: traefik:v3.0 container_name: traefik restart: unless-stopped security_opt: - no-new-privileges:true # Use bridge network mode for reliable service discovery # Service discovery works correctly with Docker labels in bridge mode ports: - "80:80" - "443:443" - "2222:2222" # Gitea SSH networks: - traefik-public environment: - TZ=Europe/Berlin command: # Load static configuration file - "--configFile=/traefik.yml" # Increase timeouts for slow backends like Gitea - "--entrypoints.websecure.transport.respondingTimeouts.readTimeout=300s" - "--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=300s" - "--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=360s" 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 - BasicAuth protected - "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 - "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$Of2wG3O5$$y8X1vEoIp9vpvx64mIalk/" # Note: ACME challenges are handled automatically by Traefik # when httpChallenge.entryPoint: web is set in traefik.yml # No explicit router needed - Traefik handles /.well-known/acme-challenge automatically # Global redirect to HTTPS (lower priority, matches everything else) # ACME challenges are excluded from redirect automatically by Traefik # Explicitly exclude ACME challenge path to be safe - "traefik.http.routers.http-catchall.rule=HostRegexp(`{host:.+}`) && !PathPrefix(`/.well-known/acme-challenge`)" - "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" healthcheck: test: ["CMD", "traefik", "healthcheck", "--ping"] interval: 30s timeout: 10s retries: 3 start_period: 10s networks: traefik-public: external: true