git clone https://github.com/ComeOnOliver/skillshub
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/traefik" ~/.claude/skills/comeonoliver-skillshub-traefik && rm -rf "$T"
skills/TerminalSkills/skills/traefik/SKILL.mdTraefik
Overview
Traefik is a modern reverse proxy and load balancer designed for containerized environments. Unlike nginx, Traefik auto-discovers services from Docker labels, Kubernetes ingress, and other providers — no manual config file updates when you add or remove services. It handles Let's Encrypt TLS certificates automatically, supports path-based and host-based routing, and offers middleware for rate limiting, authentication, headers, and more.
Instructions
Step 1: Docker Compose Deployment
# docker-compose.yml — Traefik with auto-discovery and Let's Encrypt # Traefik watches Docker events and configures routing from container labels services: traefik: image: traefik:v3.2 command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.exposedByDefault=false" # only route labeled containers - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" # Let's Encrypt auto-TLS - "--certificatesresolvers.letsencrypt.acme.tlschallenge=true" - "--certificatesresolvers.letsencrypt.acme.email=admin@example.com" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" # HTTP → HTTPS redirect - "--entrypoints.web.http.redirections.entryPoint.to=websecure" - "--entrypoints.web.http.redirections.entryPoint.scheme=https" ports: - "80:80" - "443:443" volumes: - /var/run/docker.sock:/var/run/docker.sock:ro # Docker auto-discovery - letsencrypt:/letsencrypt # TLS certificate storage labels: # Dashboard at traefik.example.com (protected by basicauth) - "traefik.enable=true" - "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" - "traefik.http.routers.dashboard.middlewares=auth" - "traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$xyz$$hashedpassword" volumes: letsencrypt:
Step 2: Route Services via Docker Labels
# docker-compose.yml — Application services with Traefik routing labels # Each service declares its own routing rules via labels — no Traefik config changes needed services: traefik: # ... (from Step 1) webapp: image: myapp:latest labels: - "traefik.enable=true" - "traefik.http.routers.webapp.rule=Host(`app.example.com`)" - "traefik.http.routers.webapp.tls.certresolver=letsencrypt" - "traefik.http.services.webapp.loadbalancer.server.port=3000" api: image: myapi:latest labels: - "traefik.enable=true" - "traefik.http.routers.api.rule=Host(`api.example.com`)" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=8000" blog: image: ghost:latest labels: - "traefik.enable=true" - "traefik.http.routers.blog.rule=Host(`blog.example.com`)" - "traefik.http.routers.blog.tls.certresolver=letsencrypt" - "traefik.http.services.blog.loadbalancer.server.port=2368"
Adding a new service is just adding labels — Traefik detects the container automatically and starts routing. No restart, no config reload.
Step 3: Path-Based Routing
# Route different paths to different services on the same domain services: frontend: image: frontend:latest labels: - "traefik.enable=true" - "traefik.http.routers.frontend.rule=Host(`example.com`)" - "traefik.http.routers.frontend.tls.certresolver=letsencrypt" - "traefik.http.services.frontend.loadbalancer.server.port=3000" api: image: api:latest labels: - "traefik.enable=true" # PathPrefix routes /api/* to this service - "traefik.http.routers.api.rule=Host(`example.com`) && PathPrefix(`/api`)" - "traefik.http.routers.api.tls.certresolver=letsencrypt" - "traefik.http.services.api.loadbalancer.server.port=8000" # Strip /api prefix before forwarding (so /api/users → /users) - "traefik.http.routers.api.middlewares=strip-api" - "traefik.http.middlewares.strip-api.stripprefix.prefixes=/api"
Step 4: Middleware
# Rate limiting labels: - "traefik.http.middlewares.rate-limit.ratelimit.average=100" # 100 req/s average - "traefik.http.middlewares.rate-limit.ratelimit.burst=200" - "traefik.http.routers.api.middlewares=rate-limit" # Security headers labels: - "traefik.http.middlewares.security.headers.stsSeconds=31536000" - "traefik.http.middlewares.security.headers.stsIncludeSubdomains=true" - "traefik.http.middlewares.security.headers.contentTypeNosniff=true" - "traefik.http.middlewares.security.headers.frameDeny=true" - "traefik.http.routers.webapp.middlewares=security" # IP whitelist (admin panel) labels: - "traefik.http.middlewares.admin-ip.ipallowlist.sourcerange=10.0.0.0/8,192.168.1.0/24" - "traefik.http.routers.admin.middlewares=admin-ip" # Basic auth labels: - "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$05$$hashhere" - "traefik.http.routers.protected.middlewares=auth" # Compress responses labels: - "traefik.http.middlewares.compress.compress=true" - "traefik.http.routers.webapp.middlewares=compress" # Chain multiple middlewares labels: - "traefik.http.routers.api.middlewares=rate-limit,security,compress"
Step 5: Load Balancing
# Scale services and Traefik auto-load-balances services: webapp: image: myapp:latest deploy: replicas: 3 # 3 instances labels: - "traefik.enable=true" - "traefik.http.routers.webapp.rule=Host(`app.example.com`)" - "traefik.http.services.webapp.loadbalancer.server.port=3000" # Health check - "traefik.http.services.webapp.loadbalancer.healthcheck.path=/health" - "traefik.http.services.webapp.loadbalancer.healthcheck.interval=10s" # Sticky sessions (if needed) - "traefik.http.services.webapp.loadbalancer.sticky.cookie.name=server_id"
Step 6: File-Based Configuration
For services outside Docker (bare metal, VMs), use file configuration:
# /etc/traefik/dynamic/services.yml — Route to external services http: routers: legacy-app: rule: "Host(`legacy.example.com`)" service: legacy-backend tls: certResolver: letsencrypt services: legacy-backend: loadBalancer: servers: - url: "http://192.168.1.50:8080" - url: "http://192.168.1.51:8080" healthCheck: path: /health interval: "15s"
# traefik.yml (static config) — Enable file provider providers: docker: exposedByDefault: false file: directory: /etc/traefik/dynamic/ watch: true # auto-reload on file changes
Examples
Example 1: Set up HTTPS for multiple Docker services on one server
User prompt: "I have 4 Docker services (app, API, admin panel, blog) that each need their own subdomain with automatic HTTPS."
The agent will:
- Deploy Traefik with Docker socket access and Let's Encrypt.
- Add routing labels to each service's docker-compose definition.
- Traefik auto-provisions TLS certificates for each subdomain.
- Add security headers and rate limiting middleware.
- Protect the admin panel with IP whitelist or basic auth.
Example 2: Zero-downtime deployments with health checks
User prompt: "Set up Traefik so I can deploy new versions without downtime. Old containers should keep serving until new ones are healthy."
The agent will:
- Configure health check endpoints on the application.
- Add Traefik health check labels with appropriate intervals.
- Use Docker's rolling update strategy with Traefik's load balancer.
- New containers only receive traffic after passing health checks.
Guidelines
- Mount the Docker socket as read-only (
) — Traefik only needs to read container labels, not manage containers.:ro - Set
to prevent accidentally routing internal services (databases, Redis) to the internet. Only containers withexposedByDefault=false
get routes.traefik.enable=true - Use Let's Encrypt's TLS challenge (port 443) rather than HTTP challenge (port 80) when possible — it's simpler and works with CDNs.
- Store the acme.json file on a persistent volume — losing it means re-issuing all certificates, which hits Let's Encrypt rate limits.
- For high-traffic production, add a health check to every service. Without health checks, Traefik routes to containers that may be starting up or shutting down.
- Traefik's Docker provider is the killer feature over nginx — adding a new service is just adding labels to docker-compose, no proxy config to update, no reload needed.