traefik
Route traffic and manage TLS with Traefik reverse proxy. Use when a user asks to set up a reverse proxy, route traffic to Docker containers, auto-provision SSL certificates with Let's Encrypt, set up load balancing, configure HTTPS for multiple services, use a modern alternative to nginx for Docker, set up path-based or host-based routing, add middleware (rate limiting, auth, headers), or manage ingress for containerized applications.
Usage
Getting Started
- Install the skill using the command above
- Open your AI coding agent (Claude Code, Codex, Gemini CLI, or Cursor)
- Reference the skill in your prompt
- The AI will use the skill's capabilities automatically
Example Prompts
- "Deploy the latest build to the staging environment and run smoke tests"
- "Check the CI pipeline status and summarize any recent failures"
Documentation
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 (
:ro) — Traefik only needs to read container labels, not manage containers. - Set
exposedByDefault=falseto prevent accidentally routing internal services (databases, Redis) to the internet. Only containers withtraefik.enable=trueget routes. - 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.
Information
- Version
- 1.0.0
- Author
- terminal-skills
- Category
- DevOps
- License
- Apache-2.0