Files
magnus919_agent-skills/traefik/references/docker-provider.md
T
Magnus Hedemark 41646af1b9 fix: format compliance, v3.7, expanded migration, serversTransport ref, templates, healthcheck
Phase 1 — Format compliance:
- Add version (0.1.0) and compatibility fields to frontmatter
- Tighten description to trigger-first style (~174 chars)
- Fix 'When NOT to Use' contradiction on plugins
- Remove non-standard spec-version from metadata

Phase 2 — Content enrichment:
- Bump all image references from v3.2 to v3.7 across 7 files
- Add pre-migration audit checklist (10 items) to migration reference
- Add tracing/provider removal detail to migration reference
- Create servers-transport.md (191 lines) extracted from
  static-configuration.md with expanded mTLS, SPIFFE, CRD coverage

Phase 3 — Templates & scripts:
- Add templates/docker-compose.yml — production compose with socket proxy,
  Let's Encrypt, dashboard auth, HTTP/3, security hardening
- Add scripts/traefik-healthcheck.sh — agent-compatible health check with
  --json output, checks ping, API, router count, certificate expiry

Signed-off-by: Jasper <magnus@groktop.us>
2026-07-05 16:12:35 -04:00

267 lines
10 KiB
Markdown

# Docker Provider Reference
Traefik's Docker provider automatically discovers containers and generates routing configuration from container labels. This is the most common way to use Traefik in development and production.
## Enabling the Docker Provider
```yaml
# Static config (traefik.yml)
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false # Secure: only expose labeled containers
network: "proxy" # Default network
defaultRule: "Host(`{{ normalize .Name }}`)"
watch: true
```
## Docker Compose — Mounting the Socket
```yaml
services:
traefik:
image: traefik:v3.7
volumes:
- /var/run/docker.sock:/var/run/docker.sock # Required
- ./traefik.yml:/etc/traefik/traefik.yml # Static config
- ./letsencrypt:/letsencrypt # ACME storage
networks:
- proxy
```
## All Docker Labels Reference
Labels follow the pattern: `traefik.<protocol>.<resource-type>.<name>.<option>=<value>`
### General Labels
| Label | Description |
|-------|-------------|
| `traefik.enable=true` | Explicitly enable this container (required when `exposedByDefault=false`) |
| `traefik.docker.network=mynetwork` | Override the default Docker network for this container |
| `traefik.docker.allowNonRunning=true` | Enable discovery of non-running containers |
### HTTP Router Labels
Prefix: `traefik.http.routers.<name>.`
| Label | Description |
|-------|-------------|
| `rule=Host(\`example.com\`)` | Router matching rule (REQUIRED — or use `defaultRule`) |
| `entrypoints=web,websecure` | EntryPoints to attach this router to |
| `middlewares=auth,ratelimit` | Comma-separated list of middleware names |
| `service=my-service` | Target service for this router (auto-assigned if omitted) |
| `tls=true` | Enable TLS |
| `tls.certresolver=letsencrypt` | Certificate resolver for automatic cert |
| `tls.domains[0].main=example.com` | Define domain for TLS certificate |
| `tls.domains[0].sans=www.example.com` | SANs for the certificate |
| `tls.options=default@file` | TLS options to apply |
| `priority=42` | Router priority (higher = matched first) |
| `ruleSyntax=v3` | Rule syntax version (v3 or v2, default: v3) |
| `observability.metrics=true` | Enable metrics for this router |
| `observability.accesslogs=true` | Enable access logs for this router |
| `observability.tracing=true` | Enable tracing for this router |
### HTTP Service Labels
Prefix: `traefik.http.services.<name>.`
| Label | Description |
|-------|-------------|
| `loadbalancer.server.port=8080` | Backend port (REQUIRED when container exposes multiple ports) |
| `loadbalancer.server.scheme=https` | Backend scheme (default: http) |
| `loadbalancer.passhostheader=true` | Forward Host header to backend |
| `loadbalancer.strategy=wrr` | Strategy: wrr, p2c, hrw, leasttime |
| `loadbalancer.sticky.cookie.name=sticky` | Enable sticky sessions via cookie |
| `loadbalancer.sticky.cookie.httponly=true` | Set HttpOnly flag on sticky cookie |
| `loadbalancer.sticky.cookie.secure=true` | Set Secure flag on sticky cookie |
| `loadbalancer.sticky.cookie.samesite=none` | SameSite attribute: none/lax/strict |
| `loadbalancer.sticky.cookie.maxage=86400` | Cookie max age in seconds |
| `loadbalancer.healthcheck.path=/health` | Health check endpoint path |
| `loadbalancer.healthcheck.interval=10s` | Health check interval |
| `loadbalancer.healthcheck.timeout=3s` | Health check timeout |
| `loadbalancer.healthcheck.hostname=example.com` | Host header for health check |
| `loadbalancer.healthcheck.scheme=https` | Scheme for health check |
| `loadbalancer.healthcheck.method=GET` | HTTP method for health check |
| `loadbalancer.healthcheck.headers.X-Custom=v` | Custom headers for health check |
| `loadbalancer.healthcheck.followredirects=true` | Follow redirects during health checks |
| `loadbalancer.passivehealthcheck.maxfailedattempts=3` | Failures before considered unhealthy |
| `loadbalancer.passivehealthcheck.failurewindow=3s` | Time window for failure counting |
| `loadbalancer.serverstransport=custom@file` | Reference to a ServersTransport |
| `loadbalancer.responseforwarding.flushinterval=150ms` | Flush interval for streaming |
### HTTP Middleware Labels
Prefix: `traefik.http.middlewares.<name>.`
Middleware types and their label syntax:
| Middleware Type | Label Syntax |
|----------------|-------------|
| `addprefix` | `traefik.http.middlewares.my-mw.addprefix.prefix=/api/v2` |
| `basicauth` | `traefik.http.middlewares.my-mw.basicauth.users=user:$$2y$$10$$...` |
| `digestauth` | `traefik.http.middlewares.my-mw.digestauth.users=user:realm:hash` |
| `forwardauth` | `traefik.http.middlewares.my-mw.forwardauth.address=http://auth:8080/verify` |
| `headers` | `traefik.http.middlewares.my-mw.headers.customrequestheaders.X-Scope=internal` |
| `ipallowlist` | `traefik.http.middlewares.my-mw.ipallowlist.sourcerange=10.0.0.0/8` |
| `ratelimit` | `traefik.http.middlewares.my-mw.ratelimit.average=100` |
| `redirectscheme` | `traefik.http.middlewares.my-mw.redirectscheme.scheme=https` |
| `redirectregex` | `traefik.http.middlewares.my-mw.redirectregex.regex=^http://(.*)` |
| `replacepath` | `traefik.http.middlewares.my-mw.replacepath.path=/fallback` |
| `replacepathregex` | `traefik.http.middlewares.my-mw.replacepathregex.regex=^/api/v1/(.*)` |
| `stripprefix` | `traefik.http.middlewares.my-mw.stripprefix.prefixes=/api,/v1` |
| `stripprefixregex` | `traefik.http.middlewares.my-mw.stripprefixregex.regex=/[a-z]+/public` |
| `retry` | `traefik.http.middlewares.my-mw.retry.attempts=3` |
| `compress` | `traefik.http.middlewares.my-mw.compress=true` |
| `circuitbreaker` | `traefik.http.middlewares.my-mw.circuitbreaker.expression=NetworkErrorRatio() > 0.5` |
| `inflightreq` | `traefik.http.middlewares.my-mw.inflightreq.amount=100` |
| `ratelimit` | `traefik.http.middlewares.my-mw.ratelimit.average=100` |
| `chain` | `traefik.http.middlewares.my-mw.chain.middlewares=mw1,mw2,mw3` |
| `errorpages` | `traefik.http.middlewares.my-mw.errorpages.status=500-599` |
| `contenttype` | `traefik.http.middlewares.my-mw.contenttype=true` |
| `grpcweb` | `traefik.http.middlewares.my-mw.grpcweb=true` |
### TCP Router Labels
Prefix: `traefik.tcp.routers.<name>.`
| Label | Description |
|-------|-------------|
| `rule=HostSNI(\`example.com\`)` | SNI matching rule |
| `entrypoints=postgres` | EntryPoints (must be TCP) |
| `service=my-service` | Target TCP service |
| `tls=true` | Enable TLS passthrough or termination |
| `tls.certresolver=letsencrypt` | Cert resolver for TLS termination |
| `tls.options=default@file` | TLS options |
| `tls.passthrough=false` | TLS passthrough (no termination) |
### TCP Service Labels
Prefix: `traefik.tcp.services.<name>.`
| Label | Description |
|-------|-------------|
| `loadbalancer.server.port=5432` | Backend port |
| `loadbalancer.server.address=10.0.0.1` | Backend IP (auto-detected if omitted) |
| `loadbalancer.server.proxyProtocol.version=1` | Enable PROXY protocol to backend |
| `loadbalancer.terminationdelay=5s` | Connection termination delay |
| `loadbalancer.sticky=false` | Enable sticky sessions |
| `loadbalancer.strategy=wrr` | Load balancing strategy |
### UDP Router Labels
Prefix: `traefik.udp.routers.<name>.`
| Label | Description |
|-------|-------------|
| `entrypoints=dns` | EntryPoints (must be UDP) |
| `service=my-service` | Target UDP service |
### UDP Service Labels
Prefix: `traefik.udp.services.<name>.`
| Label | Description |
|-------|-------------|
| `loadbalancer.server.port=53` | Backend UDP port |
## Reference Examples
### Basic Service with Custom Port
```yaml
services:
app:
image: myapp:latest
labels:
- "traefik.enable=true"
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=3000"
networks:
- proxy
```
### Multiple Routers for One Container
```yaml
labels:
- "traefik.enable=true"
# API router
- "traefik.http.routers.api.rule=Host(`api.example.com`) && PathPrefix(`/v1`)"
- "traefik.http.routers.api.service=api-service"
- "traefik.http.services.api-service.loadbalancer.server.port=8080"
# Admin router (different port)
- "traefik.http.routers.admin.rule=Host(`admin.example.com`)"
- "traefik.http.routers.admin.service=admin-service"
- "traefik.http.services.admin-service.loadbalancer.server.port=9090"
```
### With Middleware Chain
```yaml
labels:
- "traefik.enable=true"
# Middleware declarations
- "traefik.http.middlewares.auth.basicauth.users=admin:$$2y$$10$$..."
- "traefik.http.middlewares.limit.ratelimit.average=100"
- "traefik.http.middlewares.limit.ratelimit.burst=200"
- "traefik.http.middlewares.headers.customrequestheaders.X-Forwarded-Proto=https"
# Router with middleware chain
- "traefik.http.routers.app.rule=Host(`app.example.com`)"
- "traefik.http.routers.app.middlewares=auth,limit,headers"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.tls.certresolver=letsencrypt"
- "traefik.http.services.app.loadbalancer.server.port=80"
```
### Hashing Passwords for BasicAuth
```bash
# Generate a bcrypt hash for BasicAuth
htpasswd -nbB admin "my-password" | sed -e 's/\$/\$\$/g'
# Output: admin:$$2y$$05$$...
# Note: $$ escaping is required in Docker Compose files
```
### Docker Network Selection
When a container is connected to multiple Docker networks, specify the correct one:
```yaml
networks:
- proxy # Network Traefik is on
- internal # Network for backend communication
labels:
- "traefik.docker.network=proxy"
```
### Constraints
Filter which containers Traefik discovers:
```yaml
# Static config
providers:
docker:
constraints: "Label(`traefik.enable`, `true`) && !Label(`internal`, `true`)"
```
### Port Detection Rules
Traefik automatically determines the backend port:
1. If a container exposes **one** port, Traefik uses it
2. If it exposes **multiple** ports, Traefik uses the **lowest**
3. Always set `loadbalancer.server.port` to be explicit
### Security Note: Docker Socket
Mounting the Docker socket gives the container root-equivalent access to the host. For production:
- Use [docker-socket-proxy](https://github.com/Tecnativa/docker-socket-proxy) for read-only access
- Or expose the socket over SSH/TCP with TLS client certificates
- Run Traefik as a non-root user when possible (use `--users` flag)