{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreifo5tadxqmbzap2resj4czkuyrc4nwuwd47gkbqc25vikh7p6mpiq",
"uri": "at://did:plc:yaz3p6kpjacwypalo2scppxc/app.bsky.feed.post/3mn2eqratg5e2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreidokiey6qohyen6lelvyernumwmq2cxxwst36zoaqs5dalayiokdu"
},
"mimeType": "image/png",
"size": 104606
},
"description": "Traefik is the reverse proxy that configures itself. Add a container with the right labels and it appears behind HTTPS automatically — no config reload, no certbot, no manual routing rules. Here's how it works and when to use it.",
"path": "/traefik-reverse-proxy-docker-guide/",
"publishedAt": "2026-05-30T06:00:18.000Z",
"site": "https://devopspack.com",
"tags": [
"Get in touch at pipoline.com →"
],
"textContent": "Every self-hosted stack needs a reverse proxy. It's the piece that sits in front of everything else — terminating TLS, routing requests to the right container, handling certificates. Get it wrong and you're either manually editing config files every time you add a service, or running a separate tool just to manage certificates.\n\nTraefik takes a different approach. Instead of writing routing rules and reloading configs, you put labels on your Docker containers and Traefik figures out the rest. New container starts, route appears. Container stops, route disappears. Certificates get provisioned automatically via Let's Encrypt. The dashboard shows you what's routed where in real time.\n\nIt's the reverse proxy that makes the most sense for self-hosted stacks running multiple services on a single server — which is exactly the kind of setup DevOpsPack readers are running.\n\n## What Traefik is\n\nTraefik is an open-source cloud-native reverse proxy and load balancer created by Traefik Labs. The current version is v3, with v3.5 being the latest stable release as of mid-2025. It's written in Go, MIT licensed, and has 55,000+ GitHub stars.\n\nThe core philosophy: **dynamic configuration over static configuration**. Traditional reverse proxies like Nginx use static config files — you define routes, reload the daemon, routes are active. Traefik polls the Docker socket (or Kubernetes API, or Consul, or several other providers) and reconfigures routing in real time as containers start and stop. No reload required, no config file to edit.\n\nThree concepts you need to understand to use Traefik:\n\n * **Entrypoints** — the ports Traefik listens on. Typically port 80 (HTTP) and port 443 (HTTPS).\n * **Routers** — rules that match incoming requests (by hostname, path, headers) and send them to a service.\n * **Services** — the backend that receives traffic, usually a container on a specific port.\n * **Middleware** — processing between router and service: redirect HTTP to HTTPS, add auth headers, rate limit, strip path prefixes.\n\n\n\nIn Docker mode, routers and services are configured via container labels. Traefik reads these labels and builds its routing table automatically.\n\n## Basic setup with Docker Compose\n\nA minimal Traefik setup that handles HTTPS with Let's Encrypt:\n\n\n services:\n traefik:\n image: traefik:v3\n container_name: traefik\n restart: unless-stopped\n command:\n - \"--providers.docker=true\"\n - \"--providers.docker.exposedbydefault=false\"\n - \"--entrypoints.web.address=:80\"\n - \"--entrypoints.websecure.address=:443\"\n - \"--certificatesresolvers.letsencrypt.acme.httpchallenge=true\"\n - \"--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web\"\n - \"--certificatesresolvers.letsencrypt.acme.email=you@example.com\"\n - \"--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json\"\n - \"--api.dashboard=true\"\n ports:\n - \"80:80\"\n - \"443:443\"\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock:ro\n - ./letsencrypt:/letsencrypt\n labels:\n - \"traefik.enable=true\"\n - \"traefik.http.routers.traefik.rule=Host(`traefik.example.com`)\"\n - \"traefik.http.routers.traefik.tls.certresolver=letsencrypt\"\n - \"traefik.http.routers.traefik.service=api@internal\"\n\nTwo things to note: `exposedbydefault=false` means containers are not routed unless they have `traefik.enable=true` — important for security. The Docker socket is mounted read-only.\n\nNow adding any service is just labels:\n\n\n ghost:\n image: ghost:5\n restart: unless-stopped\n environment:\n url: https://devopspack.com\n labels:\n - \"traefik.enable=true\"\n - \"traefik.http.routers.ghost.rule=Host(`devopspack.com`)\"\n - \"traefik.http.routers.ghost.tls.certresolver=letsencrypt\"\n - \"traefik.http.routers.ghost.entrypoints=websecure\"\n\nTraefik reads these labels, provisions a certificate for `devopspack.com`, and starts routing HTTPS traffic to the Ghost container. No config file edit. No reload.\n\n## HTTP to HTTPS redirect\n\nAdd a global middleware to redirect all HTTP traffic to HTTPS — define it once on the Traefik container and it applies everywhere:\n\n\n - \"--entrypoints.web.http.redirections.entrypoint.to=websecure\"\n - \"--entrypoints.web.http.redirections.entrypoint.scheme=https\"\n - \"--entrypoints.web.http.redirections.entrypoint.permanent=true\"\n\n## Wildcard certificates with DNS-01\n\nHTTP-01 challenge requires the domain to be publicly accessible on port 80. For internal services — Grafana, Uptime Kuma, Authentik, Gitea — that aren't exposed to the internet but still need HTTPS, you want DNS-01 challenge instead. This proves domain ownership through a DNS TXT record rather than an HTTP request, so the service doesn't need to be publicly reachable.\n\nTraefik supports DNS-01 with most major DNS providers. With Cloudflare:\n\n\n traefik:\n environment:\n CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN}\n command:\n - \"--certificatesresolvers.cloudflare.acme.dnschallenge=true\"\n - \"--certificatesresolvers.cloudflare.acme.dnschallenge.provider=cloudflare\"\n - \"--certificatesresolvers.cloudflare.acme.email=you@example.com\"\n - \"--certificatesresolvers.cloudflare.acme.storage=/letsencrypt/acme.json\"\n\nThen on any internal service:\n\n\n labels:\n - \"traefik.http.routers.grafana.rule=Host(`grafana.internal.example.com`)\"\n - \"traefik.http.routers.grafana.tls.certresolver=cloudflare\"\n\nOne DNS API token, wildcard certificate provisioned automatically, HTTPS working on an internal service with no public exposure.\n\n## Middleware: security headers, auth, rate limiting\n\nMiddleware is where Traefik gets powerful. Define a middleware once, reference it on any router.\n\n**Security headers — apply to all routers:**\n\n\n labels:\n - \"traefik.http.middlewares.secure-headers.headers.stsSeconds=31536000\"\n - \"traefik.http.middlewares.secure-headers.headers.stsIncludeSubdomains=true\"\n - \"traefik.http.middlewares.secure-headers.headers.contentTypeNosniff=true\"\n - \"traefik.http.middlewares.secure-headers.headers.browserXssFilter=true\"\n - \"traefik.http.middlewares.secure-headers.headers.referrerPolicy=strict-origin-when-cross-origin\"\n\n**Basic auth for the Traefik dashboard:**\n\n\n # Generate with: echo $(htpasswd -nb user password) | sed -e s/\\\\$/\\\\$\\\\$/g\n - \"traefik.http.middlewares.auth.basicauth.users=user:$$apr1$$...\"\n - \"traefik.http.routers.traefik.middlewares=auth\"\n\n**Rate limiting:**\n\n\n - \"traefik.http.middlewares.ratelimit.ratelimit.average=100\"\n - \"traefik.http.middlewares.ratelimit.ratelimit.burst=50\"\n\n**IP allowlist — restrict a service to internal IPs only:**\n\n\n - \"traefik.http.middlewares.internal-only.ipallowlist.sourcerange=192.168.0.0/16,10.0.0.0/8\"\n\n## HTTP/3 and QUIC\n\nTraefik v3 added native HTTP/3 (QUIC) support. Enable it per entrypoint:\n\n\n - \"--entrypoints.websecure.http3=true\"\n - \"--entrypoints.websecure.http3.advertisedPort=443\"\n\nYou'll also need to expose UDP 443:\n\n\n ports:\n - \"443:443/tcp\"\n - \"443:443/udp\"\n\nHTTP/3 improves performance for clients on high-latency or unreliable connections by using QUIC's connection migration and 0-RTT handshakes. For most self-hosted setups it's a minor improvement; for high-traffic sites it matters more.\n\n## The Traefik dashboard\n\nTraefik ships with a built-in dashboard showing your active routers, services, middleware, and entrypoints in real time. It's read-only — you can't make changes from it — but it's invaluable for debugging routing issues and understanding what Traefik has discovered.\n\nKeep it behind auth (`basicauth` middleware or Authentik forward auth) and either IP allowlist or a private DNS entry. The dashboard exposes your infrastructure map — don't leave it open to the internet.\n\n## File-based configuration for non-Docker services\n\nNot everything runs in Docker. Legacy apps, services on other servers, or anything that doesn't support container labels can be routed through Traefik using the file provider:\n\n\n # traefik/dynamic/legacy.yml\n http:\n routers:\n legacy-app:\n rule: \"Host(`legacy.example.com`)\"\n service: legacy-app\n tls:\n certResolver: letsencrypt\n\n services:\n legacy-app:\n loadBalancer:\n servers:\n - url: \"http://192.168.1.50:8080\"\n\nEnable the file provider in your Traefik command:\n\n\n - \"--providers.file.directory=/traefik/dynamic\"\n - \"--providers.file.watch=true\"\n\nTraefik watches the directory and picks up changes without a restart. This is how you route to services outside Docker — other servers on your LAN, bare metal apps, VMs.\n\n## Traefik vs Nginx vs Caddy\n\n**Nginx** — the performance king. Lowest latency, highest throughput per CPU core, battle-tested at every scale. Static config files, manual certificate management (or certbot), no automatic service discovery. Right choice for static-heavy workloads, caching, and when you need the finest-grained control over request handling.\n\n**Caddy** — the simplest path to automatic HTTPS. Caddyfile syntax is minimal and readable. Certificates are automatic without any configuration at all. No dashboard, no middleware ecosystem as rich as Traefik's, no Docker label-based auto-discovery. Right choice for simple setups where you want HTTPS to just work without thinking about it.\n\n**Traefik** — the dynamic proxy for multi-service Docker environments. Auto-discovery, rich middleware, dashboard, DNS-01 wildcard certs, HTTP/3. Higher resource usage than Nginx, more initial complexity than Caddy. Right choice when you're running 5+ services in Docker and don't want to edit a proxy config every time you add one.\n\nThe practical rule: _choose Traefik when your services churn; choose Nginx when they don't._ A server running 10 self-hosted tools in Docker — Ghost, Gitea, Grafana, Uptime Kuma, Authentik, Postiz, NetBird, Cal.com — is exactly the environment Traefik is designed for.\n\n## Traefik with NetBird and Authentik\n\nTwo tools we've covered on DevOpsPack integrate particularly well with Traefik:\n\n**NetBird** requires Traefik as the external reverse proxy for its built-in reverse proxy feature. TLS passthrough support, which Traefik provides, is a hard requirement for the NetBird proxy to work correctly.\n\n**Authentik** integrates with Traefik via forward authentication — Traefik sends each request to Authentik for verification before forwarding it to the backend. This gives you SSO protection on any service, even ones that don't support OIDC natively:\n\n\n labels:\n - \"traefik.http.middlewares.authentik.forwardauth.address=http://authentik:9000/outpost.goauthentik.io/auth/traefik\"\n - \"traefik.http.middlewares.authentik.forwardauth.trustForwardHeader=true\"\n - \"traefik.http.middlewares.authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups\"\n # Apply to any service:\n - \"traefik.http.routers.myservice.middlewares=authentik\"\n\n## My take\n\nTraefik is the reverse proxy I run on every multi-service self-hosted server. The label-based Docker integration removes an entire category of operational work — I don't think about certificate renewal, I don't edit proxy configs when adding services, and the dashboard makes it immediately obvious when something isn't routing correctly.\n\nThe initial setup has a learning curve: the entrypoint/router/service/middleware model takes a bit to internalize, and Docker socket security deserves attention. But once it's running, it's one of those pieces of infrastructure you configure once and then genuinely forget about.\n\nFor anyone running a self-hosted stack — Ghost, Gitea, Grafana, Authentik, Uptime Kuma, or any combination of the tools covered on this blog — Traefik is the routing layer that ties it all together cleanly.\n\n* * *\n\nPIPOLINE · DEVOPS CONSULTING\n\n### Need help setting up Traefik?\n\nGetting Traefik right — DNS-01 wildcard certificates, Authentik forward auth, file provider for non-Docker services, security middleware — takes time to get right the first time. I can set up a production-ready Traefik stack for your server, wired into your existing services. You get automatic HTTPS and proper routing without spending a day reading documentation.\n\nGet in touch at pipoline.com →",
"title": "Traefik: The Reverse Proxy That Configures Itself",
"updatedAt": "2026-05-30T06:00:18.213Z"
}