Traefik — Cloud-Native Reverse Proxy with Service Discovery
Practical guide to Traefik v3 — reverse proxy and load balancer with automatic service discovery, middlewares and TLS via Let's Encrypt for Docker.
Traefik is a modern, cloud-native reverse proxy and load balancer that wires up your services for you. Its signature trick is automatic service discovery: through providers for Docker, Kubernetes or file-based configuration, Traefik continuously reads which containers and backends exist and builds its routers and services at runtime – with no reload. TLS is just as effortless: with a certificate resolver, Traefik fetches and renews Let's Encrypt certificates on its own. This guide takes you from the static base configuration through Docker labels and middlewares to the router rules that let you steer traffic with precision.
CLI & Static Configuration
traefik --configFile=<path> — Start Traefik with a specific configuration file.
traefik --configFile=/etc/traefik/traefik.ymltraefik version — Show the Traefik version.
traefik versiontraefik healthcheck — Run a health check against a running Traefik instance.
traefik healthcheck --pingentryPoints: — Define entry points for HTTP and HTTPS traffic (traefik.yml).
entryPoints:
web:
address: ":80"
websecure:
address: ":443"api: — Enable the Traefik dashboard. insecure: true exposes it unprotected and belongs in development only – in production, secure the dashboard behind a router and middleware.
api:
dashboard: true
insecure: true # Access at http://localhost:8080providers.docker: — Enable the Docker provider for auto-discovery of containers. The mounted Docker socket grants root-equivalent access – mount it read-only (:ro) and restrict access tightly.
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: falseproviders.file: — Enable file-based dynamic configuration with auto-reload.
providers:
file:
directory: /etc/traefik/dynamic/
watch: trueDocker Labels — Routing
traefik.enable=true — Enable Traefik for this container (when exposedByDefault is false).
labels:
- traefik.enable=truetraefik.http.routers.<name>.rule=Host(`<domain>`) — Route traffic based on the hostname.
labels:
- traefik.http.routers.myapp.rule=Host(`app.example.com`)traefik.http.routers.<name>.rule=Host(`<domain>`) && PathPrefix(`<path>`) — Route based on hostname and URL path prefix.
labels:
- traefik.http.routers.api.rule=Host(`example.com`) && PathPrefix(`/api`)traefik.http.routers.<name>.entrypoints=<entry> — Specify which entry points the router should listen on.
labels:
- traefik.http.routers.myapp.entrypoints=websecuretraefik.http.services.<name>.loadbalancer.server.port=<port> — Set the port of the backend service inside the container.
labels:
- traefik.http.services.myapp.loadbalancer.server.port=8080traefik.http.routers.<name>.priority=<n> — Set the router priority (higher number = higher priority).
labels:
- traefik.http.routers.specific.priority=100Docker Labels — TLS & Let's Encrypt
traefik.http.routers.<name>.tls=true — Enable TLS for a router.
labels:
- traefik.http.routers.myapp.tls=truetraefik.http.routers.<name>.tls.certresolver=<resolver> — Use a certificate resolver (Let's Encrypt) for automatic TLS.
labels:
- traefik.http.routers.myapp.tls.certresolver=letsencryptcertificatesResolvers (HTTP-01): — Configure Let's Encrypt with the HTTP-01 challenge (traefik.yml).
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /etc/traefik/acme.json
httpChallenge:
entryPoint: webcertificatesResolvers (DNS-01): — Use the DNS-01 challenge for wildcard certificates.
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /etc/traefik/acme.json
dnsChallenge:
provider: cloudflaretraefik.http.routers.<name>.tls.domains[0].main=<domain> — Set the main domain for the TLS certificate.
labels:
- traefik.http.routers.myapp.tls.domains[0].main=example.com
- traefik.http.routers.myapp.tls.domains[0].sans=*.example.comDocker Labels — Middleware
traefik.http.routers.<name>.middlewares=<middleware> — Attach middleware to a router.
labels:
- traefik.http.routers.myapp.middlewares=redirect-httpstraefik.http.middlewares.<name>.redirectscheme.scheme=https — Redirect HTTP to HTTPS.
labels:
- traefik.http.middlewares.redirect-https.redirectscheme.scheme=https
- traefik.http.middlewares.redirect-https.redirectscheme.permanent=truetraefik.http.middlewares.<name>.basicauth.users=<user:hash> — Add HTTP Basic Authentication.
labels:
- traefik.http.middlewares.auth.basicauth.users=admin:$$apr1$$hashtraefik.http.middlewares.<name>.headers.sslRedirect=true — Force SSL redirect via headers middleware.
labels:
- traefik.http.middlewares.security.headers.sslRedirect=truetraefik.http.middlewares.<name>.stripprefix.prefixes=<path> — Strip a path prefix before forwarding to the backend.
labels:
- traefik.http.middlewares.strip-api.stripprefix.prefixes=/apitraefik.http.middlewares.<name>.ratelimit.average=<n> — Rate limiting: allow n requests per second on average.
labels:
- traefik.http.middlewares.ratelimit.ratelimit.average=100
- traefik.http.middlewares.ratelimit.ratelimit.burst=50traefik.http.middlewares.<name>.compress=true — Enable gzip compression for responses.
labels:
- traefik.http.middlewares.gzip.compress=truetraefik.http.middlewares.<name>.ipallowlist.sourcerange=<cidr> — Restrict access to specific IP ranges.
labels:
- traefik.http.middlewares.internal.ipallowlist.sourcerange=10.0.0.0/8,172.16.0.0/12Docker Compose — Full Example
services: (Compose) — Basic Traefik service in Docker Compose. The Docker socket is mounted read-only (:ro) – access to it is root-equivalent.
services:
traefik:
image: traefik:v3.3
command:
- --providers.docker=true
- --entrypoints.web.address=:80
ports:
- "80:80"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:roservices: (App labels) — Application service with Traefik labels for auto-discovery.
services:
app:
image: myapp:latest
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`app.example.com`)
- traefik.http.routers.app.tls.certresolver=letsencryptnetworks: — Use a shared external network so Traefik can reach services in other compose files.
# Create first: docker network create traefik-net
networks:
default:
name: traefik-net
external: trueFile-Based Dynamic Configuration
http.routers: — Define a router in a YAML dynamic configuration file.
# /etc/traefik/dynamic/myapp.yml
http:
routers:
myapp:
rule: "Host(`example.com`)"
service: myapp
tls:
certResolver: letsencrypthttp.services: — Define a service pointing to a backend server.
http:
services:
myapp:
loadBalancer:
servers:
- url: "http://10.0.0.1:8080"
- url: "http://10.0.0.2:8080"tls.certificates: — Load custom TLS certificates from files.
tls:
certificates:
- certFile: /etc/traefik/certs/example.com.pem
keyFile: /etc/traefik/certs/example.com-key.pemLogging & Debugging
log: — Set the log level (DEBUG, INFO, WARN, ERROR).
log:
level: INFO
filePath: /var/log/traefik/traefik.logaccessLog: {} — Enable access logging for all requests.
accessLog:
filePath: /var/log/traefik/access.log
format: jsonping: {} — Enable the /ping health endpoint.
ping:
entryPoint: webmetrics: — Enable the Prometheus metrics endpoint.
metrics:
prometheus:
entryPoint: metrics
addEntryPointsLabels: true
addServicesLabels: trueUseful Router Rules
Host(`<domain>`) — Match requests by hostname.
Host(`example.com`)Host(`<domain>`) || Host(`<domain2>`) — Match multiple hostnames.
Host(`example.com`) || Host(`www.example.com`)PathPrefix(`<path>`) — Match requests by URL path prefix.
PathPrefix(`/api`)Path(`<path>`) — Match an exact URL path.
Path(`/health`)Headers(`<key>`, `<value>`) — Match requests by header value.
Headers(`X-Custom-Header`, `special-value`)HostRegexp(`{subdomain:[a-z]+}.example.com`) — Match hostnames with a regular expression.
HostRegexp(`{subdomain:[a-z]+}.example.com`)ClientIP(`<cidr>`) — Match requests from specific client IP ranges.
ClientIP(`10.0.0.0/8`) Conclusion
Traefik takes most of the manual proxy upkeep off your hands: new containers show up automatically as routers and services via labels, and Let's Encrypt certificates are issued and renewed without a cron job. Keep a clean separation between what is static (entry points, providers, resolvers) and what arrives dynamically (labels or the file provider) – that keeps your configuration manageable even with many services. And mind the security basics: never expose the dashboard unprotected, and mount the Docker socket read-only.
Further Reading
- Traefik – official documentation – reference and manual
- Traefik – GitHub repository – source code and releases