Files
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

108 lines
3.3 KiB
YAML

# Production Traefik Deployment — Docker Compose
# Target: Traefik v3.7+
# Usage: docker compose up -d
#
# Features:
# - Docker provider (read-only socket via docker-socket-proxy)
# - Let's Encrypt ACME (HTTP-01 challenge)
# - Dashboard with BasicAuth (internal-only)
# - Security hardening (read-only rootfs, no-new-privileges, capability drop)
# - Prometheus metrics endpoint
# - JSON structured logging
# - HTTP/3 (QUIC) enabled
version: "3.8"
x-logging: &default-logging
driver: json-file
options:
max-size: "10m"
max-file: "3"
services:
# --- Docker Socket Proxy (Security) ---
# Replaces direct docker.sock mount with a read-only API proxy
docker-proxy:
image: tecnativa/docker-socket-proxy:latest
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- CONTAINERS=1
- NETWORKS=1
- SERVICES=1
- TASKS=1
- INFO=1
networks:
- traefik
logging: *default-logging
# --- Traefik Reverse Proxy ---
traefik:
image: traefik:v3.7
restart: unless-stopped
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
networks:
- traefik
ports:
- "80:80"
- "443:443"
# UDP port for HTTP/3 (QUIC)
- "443:443/udp"
environment:
# DNS challenge credentials (example: Cloudflare)
# - CF_DNS_API_TOKEN=${CF_DNS_API_TOKEN}
- TZ=UTC
volumes:
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./dynamic:/etc/traefik/dynamic:ro
- ./letsencrypt:/letsencrypt
# Do NOT mount docker.sock directly — use docker-proxy
command:
# Providers
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://docker-proxy:2375"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=traefik"
# File provider for shared middlewares
- "--providers.file.directory=/etc/traefik/dynamic"
- "--providers.file.watch=true"
# EntryPoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.websecure.http3=true"
# TLS
- "--certificatesresolvers.letsencrypt.acme.email=admin@example.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
# API (dashboard served through a router, not directly)
- "--api.dashboard=true"
- "--api.insecure=false"
# Logging
- "--log.level=INFO"
- "--log.format=json"
- "--accesslog=true"
- "--accesslog.format=json"
- "--accesslog.addinternals=false"
labels:
# Dashboard router
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.tls=true"
- "traefik.http.routers.dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.dashboard.middlewares=dashboard-auth"
- "traefik.http.middlewares.dashboard-auth.basicauth.users=${DASHBOARD_AUTH:-admin:$$2y$$10$$...}"
logging: *default-logging
networks:
traefik:
name: traefik
driver: bridge