Traefik
Traefik is an open-source Edge Router for Docker, and Kubernetes that makes publishing your services a fun and easy experience. It receives requests on behalf of your system and finds out which components are responsible for handling them.
Documentation & Project Homepage: Traefik Docs
Two kinds of configuration: static (traefik.yml or CLI flags: entrypoints, providers, resolvers, log) is read at start-up; dynamic (routers, services, middlewares, TLS, from labels, the file provider or Kubernetes) reloads live.
Run with Docker Compose #
services:
traefik:
image: traefik:v3
container_name: traefik
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro
- ./acme:/acmeMounting docker.sock (even read-only) is powerful. Consider a socket proxy for production.
Dashboard and API #
Enable it in the static configuration. Do not use insecure: true on anything reachable from outside.
api:
dashboard: true
insecure: falseExpose it through a router with authentication (labels on the Traefik container):
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.example.com`)"
- "traefik.http.routers.dashboard.entrypoints=websecure"
- "traefik.http.routers.dashboard.tls.certresolver=yourresolver"
- "traefik.http.routers.dashboard.service=api@internal"
- "traefik.http.routers.dashboard.middlewares=dashboard-auth"
# generate with: htpasswd -nB admin (double every $ as $$ in labels)
- "traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$2y$$05$$..."EntryPoints #
Ports Traefik listens on.
HTTP Redirection #
entryPoints:
web:
address: :80
http:
redirections:
entryPoint:
to: websecure
scheme: httpsHTTPS #
entryPoints:
websecure:
address: :443
http:
tls:
certResolver: yourresolverSetting tls.certResolver on the entrypoint makes it the default for every router on it.
Routers #
Docker labels. router is a name you choose.
| LABEL | DESCRIPTION |
|---|---|
traefik.enable=true | Expose this container (needed when exposedByDefault: false) |
traefik.http.routers.router.entrypoints=websecure | Entrypoint for the router. Use together with tls |
traefik.http.routers.router.rule=Host(app.example.com) | Match rule (also PathPrefix, Headers, &&, ||) |
traefik.http.routers.router.tls=true | Enable TLS on the router |
traefik.http.routers.router.tls.certresolver=yourresolver | Certificate resolver for the router |
traefik.http.routers.router.middlewares=mw1,mw2 | Attach middlewares |
traefik.http.services.router.loadbalancer.server.port=8080 | Container port to forward to (needed if the image exposes several or none) |
PathPrefix and StripPrefix #
- "traefik.enable=true"
- "traefik.http.routers.nginx-test.entrypoints=websecure"
- "traefik.http.routers.nginx-test.tls=true"
- "traefik.http.routers.nginx-test.rule=PathPrefix(`/nginx-test`)"
- "traefik.http.routers.nginx-test.middlewares=nginx-test"
- "traefik.http.middlewares.nginx-test.stripprefix.prefixes=/nginx-test"Middlewares #
Common ones, as labels (name is yours):
# redirect to a different scheme or host
- "traefik.http.middlewares.name.redirectscheme.scheme=https"
# basic auth
- "traefik.http.middlewares.name.basicauth.users=user:$$apr1$$..."
# security headers
- "traefik.http.middlewares.name.headers.stsSeconds=31536000"
# rate limit
- "traefik.http.middlewares.name.ratelimit.average=100"
# allow only some source IPs (v3 name)
- "traefik.http.middlewares.name.ipallowlist.sourcerange=192.168.0.0/16"Traefik v2 names the last one ipwhitelist.
CertificatesResolvers #
httpChallenge #
certificatesResolvers:
yourresolver:
acme:
email: "your-mail-address"
storage: /acme/acme.json
httpChallenge:
entryPoint: webdnsChallenge #
DNS providers such as cloudflare, digitalocean, civo, and more. For the full list and the environment variables each needs, see the Traefik ACME Documentation. Required for wildcard certificates.
certificatesResolvers:
yourresolver:
acme:
email: "your-mail-address"
storage: /acme/acme.json
# caServer: https://acme-staging-v02.api.letsencrypt.org/directory # for testing
dnsChallenge:
provider: your-dns-provider
resolvers:
- "1.1.1.1:53"Provider credentials are passed as environment variables, e.g. CF_DNS_API_TOKEN for Cloudflare. acme.json must have permissions 600. See also Cert-Manager for the Kubernetes-native alternative.
ServersTransport #
InsecureSkipVerify #
To skip TLS verification from Traefik to your backend servers (for example self-signed backends), add this to the static config:
serversTransport:
insecureSkipVerify: trueTLS Settings #
Dynamic configuration (file provider).
defaultCertificates #
tls:
stores:
default:
defaultCertificate:
certFile: /your-traefik-cert.crt
keyFile: /your-traefik-key.keyoptions #
Set a minimum TLS version (this disables TLS 1.0 and 1.1). See SSL Security Cheat-Sheet.
tls:
options:
default:
minVersion: VersionTLS12mTLS (Client Certificates) #
Define a TLS option that requires client certificates (dynamic config), then attach it to a router. See mTLS (Mutual TLS) for creating the CA and client certificates.
tls:
options:
mtls:
clientAuth:
caFiles:
- /certs/ca.crt
clientAuthType: RequireAndVerifyClientCertclientAuthType | MEANING |
|---|---|
NoClientCert | Do not ask for a certificate |
RequestClientCert | Ask, but accept none or an unverified one |
RequireAnyClientCert | Require one, not verified against the CA |
VerifyClientCertIfGiven | Optional, but verified if sent |
RequireAndVerifyClientCert | Required and verified (what mTLS normally means) |
Attach it with a label, or tls: options: mtls in a file-provider router:
labels:
- traefik.http.routers.app.tls=true
- traefik.http.routers.app.tls.options=mtls@filePass the client certificate to the backend with the passTLSClientCert middleware (sets X-Forwarded-Tls-Client-Cert and X-Forwarded-Tls-Client-Cert-Info):
http:
middlewares:
pass-cert:
passTLSClientCert:
pem: trueTo present a client certificate to a backend, use a ServersTransport (certificates takes a list of paths, rootCAs the backend CA) and set loadBalancer.serversTransport on the service.
Documentation: TLS options · PassTLSClientCert · ServersTransport
Providers #
File #
providers:
file:
directory: /etc/traefik/dynamic
watch: trueDocker #
With exposedByDefault: false, Traefik won’t expose any containers unless they carry the label traefik.enable=true.
providers:
docker:
exposedByDefault: false
network: proxy # network shared with Traefik when a container has severalKubernetes #
providers:
kubernetesCRD: {} # IngressRoute, Middleware and other CRDs
kubernetesIngress: {} # standard Ingress objectsTraefik’s CRD API group is traefik.io/v1alpha1 (v3 and later v2 releases); older v2 uses traefik.containo.us/v1alpha1. K3s ships Traefik by default. For an IngressRoute example see Argo CD.
Log #
log:
level: ERROR # DEBUG when troubleshooting
accessLog: {} # enable the access logGlobal #
global:
checkNewVersion: true
sendAnonymousUsage: falseTroubleshooting #
| COMMAND | DESCRIPTION |
|---|---|
docker logs traefik | Start-up and routing errors |
curl -s http://localhost:8080/api/http/routers | List routers (needs the API on 8080, keep it private) |
traefik healthcheck --ping | Health check (needs ping: {} in the static config) |
404 page not found: no router matched. Check the Host rule, entrypoint and that the container is on the same Docker network.Bad Gateway(502): wrong backend port, setloadbalancer.server.port.- Certificate not issued: check
docker logs traefikfor ACME errors and thatacme.jsonischmod 600.