Traefik reverse proxy for Docker automating certificate management and middleware configuration

Key takeaways

Traefik is a Docker-native reverse proxy. It reads container labels and reconfigures routes on the fly, so adding a service is one Compose edit, not an nginx -s reload and a sysadmin ticket.

Pick Traefik when your services churn; keep NGINX when they don’t. Container-rich workloads (microservices, multi-tenant SaaS, preview environments) win with Traefik’s automatic discovery; a static, high-RPS front-end is still cheaper on NGINX or HAProxy.

Free Let’s Encrypt, built in. Traefik renews certificates automatically via ACME. Single domains use HTTP-01; wildcards need DNS-01 and a supported provider (Cloudflare, Route 53, GCloud DNS).

v3 is the version to start on in 2026. Traefik v3 has been GA since April 2024; the current release is v3.7 (v3.7.10, July 2026). It ships GA HTTP/3, native OpenTelemetry, WASM middleware, the Kubernetes Gateway API and SPIFFE. The v2→v3 migration is gentle.

This guide ships the full config. You’ll leave with a working traefik.yml + docker-compose.yml, automated TLS, the dashboard, security middlewares, wildcard certs, and the K8s and multi-tenant patterns we run in production.

Why Fora Soft wrote this guide

Fora Soft has shipped real-time video, AI, and SaaS products since 2005 — 250+ delivered products, 50 in-house engineers, a 100% job-success score on Upwork. Behind almost every one of those products, a reverse proxy does the boring, important work: TLS termination, routing, rate limiting, auth, header rewrites. This is the Traefik configuration we actually run, not a Hello World.

The original version of this post won the 2022 HackerNoon Noonies award for Containers. What you’re reading is the 2026 rebuild: Traefik v3.7, GA HTTP/3, wildcard certificates, OpenTelemetry, the Kubernetes Gateway API, and the security hardening we add by default. If you’d rather have the engineers who run that stack build it with you, jump to the closing section.

Stuck on Traefik, NGINX, or your container infra?

We do backend, DevOps and real-time video infrastructure for SaaS, surveillance and edutainment. Bring your config and we’ll review it, or build it for you.

Book a 30-min call → WhatsApp → Email us →

What Traefik is, in one paragraph

Traefik is a cloud-native reverse proxy and load balancer that watches your service registry (Docker, Kubernetes, Consul, Nomad, ECS) and builds its routes from labels, with no hand-written nginx.conf. You declare a container with a label like traefik.http.routers.api.rule=Host(`api.example.com`); the container starts, Traefik picks it up, requests a Let’s Encrypt certificate, and starts routing. The service stops and the route disappears. That’s the whole mental model, and Figure 1 shows it end to end.

Traefik request path (Client, EntryPoint, Router, Middlewares, Service) plus the Docker label discovery loop that builds it

Figure 1. The request path on top; the Docker discovery loop that builds it underneath. Only the provider changes on Kubernetes or Consul.

Traefik vs NGINX vs Caddy: pick by churn, not by hype

The honest answer to “which reverse proxy” is: it depends on how often your services change and how much raw throughput you need. NGINX and HAProxy win on peak requests-per-second; Traefik wins on operational simplicity when containers come and go. Here is how the three compare on the dimensions that actually decide a project.

Dimension Traefik v3 NGINX Caddy
Service discovery Native (Docker, K8s, Consul, ECS, Nomad) Manual, or via NGINX Ingress Plugin-based, smaller ecosystem
Auto TLS (Let’s Encrypt) Built-in (HTTP-01, DNS-01, TLS-ALPN-01) Via certbot or NGINX Plus Built-in (best in class)
HTTP/3 & QUIC GA in v3 (one entry-point flag) Yes (recent) Yes
Raw throughput Mid-tier (∼ 15–25k rps/core) High Good
Config style Static YAML/TOML + dynamic labels Imperative nginx.conf + reloads Caddyfile (declarative, terse)
Dashboard / observability Built-in dashboard, native OTel, metrics Plus only, or external Limited
Best fit Microservices, multi-tenant SaaS, preview envs High-RPS static front, raw performance Small static sites, homelab

On raw numbers, be honest with yourself: in HAProxy’s own Kubernetes-ingress benchmark, HAProxy pushed roughly 42k rps, Traefik about 19k, and the NGINX ingress about 12k (a vendor test, and the NGINX config was throughput-limited). The takeaway isn’t a scoreboard — it’s that below ~10k rps the difference is noise, and above it you’re choosing raw speed (NGINX/HAProxy) against dynamic config (Traefik). Figure 2 turns that into a decision you can make in under a minute.

Decision tree: pick Traefik vs NGINX vs Caddy vs HAProxy by service churn and required requests per second per core

Figure 2. Walk the trunk; the first Yes routes you to a proxy. Churn beats hype.

Reach for Traefik when: your services come and go (microservices, preview environments, multi-tenant deploys), you want auto-TLS without scripting certbot, and you can spend a single-digit percentage of CPU on the proxy in exchange for operational simplicity.

Reach for NGINX or HAProxy when: the edge is a stable, high-RPS front-end, you need every last request per second per core, or an experienced team already runs it well. Don’t migrate a working static edge just for the badge.

Reach for Caddy when: you want the simplest possible automatic HTTPS for a handful of static sites or a homelab, and you don’t need Docker/K8s service discovery or a dashboard. It’s the shortest config of the three.

The clearest way to feel the Traefik vs NGINX difference is the same HTTPS route in both. NGINX wants a server block, a certbot-managed certificate, and an nginx -s reload; Traefik wants two labels on the container and reloads nothing:

# NGINX — edit nginx.conf, run certbot, then: nginx -s reload
server {
  listen 443 ssl;
  server_name api.example.com;
  ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
  location / { proxy_pass http://api:8000; }
}

# Traefik — add labels to the container, no reload, cert issued automatically
labels:
  - traefik.http.routers.api.rule=Host(`api.example.com`)
  - traefik.http.routers.api.entrypoints=https
  - traefik.http.routers.api.tls.certresolver=simple-resolver
  - traefik.http.services.api.loadbalancer.server.port=8000

NGINX still wins where that reload is rare and throughput is everything: a stable, high-RPS front-end, mature tooling, and a team that already knows it. Traefik wins the moment routes change often enough that editing and reloading a config file becomes the bottleneck.

A minimal production-shaped traefik.yml

This is the static config we start every project from. It defines the HTTP and HTTPS entry points, redirects HTTP→HTTPS, enables the Docker provider, sets up an ACME resolver against Let’s Encrypt, and turns on the dashboard and metrics.

# traefik.yml — static config

log:
  level: INFO

api:
  dashboard: true
  insecure: true   # only safe behind an ssh tunnel; lock down in prod

providers:
  docker:
    exposedByDefault: false   # opt in per service via labels

entryPoints:
  http:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: https
          scheme: https
          permanent: true
  https:
    address: ":443"
    http3: {}                 # HTTP/3 is GA in v3 — no experimental flag

certificatesResolvers:
  simple-resolver:
    acme:
      email: ops@example.com
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: http

accessLog:
  format: json
metrics:
  prometheus: {}              # /metrics endpoint for Prometheus

Companion docker-compose.yml

services:
  traefik:
    image: traefik:v3.7                     # current stable line in 2026
    container_name: traefik
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"                       # HTTP/3 needs UDP 443
      - "127.0.0.1:8080:8080"               # dashboard, ssh-tunnel only
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./traefik.yml:/etc/traefik/traefik.yml:ro
      - /data/letsencrypt:/letsencrypt
    networks:
      - traefik

  whoami:
    image: traefik/whoami
    restart: always
    labels:
      - traefik.enable=true
      - traefik.http.routers.whoami.rule=Host(`example.com`)
      - traefik.http.routers.whoami.entrypoints=https
      - traefik.http.routers.whoami.tls.certresolver=simple-resolver
      - traefik.http.services.whoami.loadbalancer.server.port=80
    networks:
      - traefik

networks:
  traefik:
    external: true

Run docker network create traefik once, then docker compose up -d. Hit https://example.com and you should see the whoami output behind a green padlock.

One caveat before production: mounting /var/run/docker.sock, even read-only, gives Traefik root-equivalent reach into the host. On anything internet-facing we put a read-only Docker socket proxy in front of it (the community now favors wollomatic/socket-proxy), run Traefik as non-root with a read-only filesystem, and never expose the raw socket. More on that in the pitfalls.

Reaching the dashboard safely

The dashboard is bound to 127.0.0.1:8080 on the host, so it isn’t exposed to the internet. Open it over an SSH port-forward:

ssh -L 8080:localhost:8080 root@example.com
# then open http://localhost:8080 in your browser

If the dashboard has to be reachable remotely, route api@internal through Traefik behind a basic-auth plus IP-allowlist middleware, and turn off insecure. Never leave api.insecure: true on a public port.

Middlewares we ship by default

Three middlewares cover most real-world needs: basic auth, security headers, and rate limiting. Middlewares run in the order you attach them, so put auth and rate limits in front of the service and headers on the way back out. Figure 3 shows where they sit in a request’s path.

A request through a Traefik router: TLS, routing, then the middleware chain (headers, rate limit, auth) before the service

Figure 3. EntryPoint to service, with the observability taps Traefik v3 exposes at every hop.

# add to a service’s labels in docker-compose.yml

# 1) basic auth on the dashboard
- traefik.http.middlewares.dashboard-auth.basicauth.users=admin:$$apr1$$Cyl...   # htpasswd

# 2) security headers (HSTS, X-Frame, nosniff)
- traefik.http.middlewares.sec-headers.headers.stsSeconds=31536000
- traefik.http.middlewares.sec-headers.headers.stsIncludeSubdomains=true
- traefik.http.middlewares.sec-headers.headers.contentTypeNosniff=true
- traefik.http.middlewares.sec-headers.headers.browserXssFilter=true
- traefik.http.middlewares.sec-headers.headers.frameDeny=true

# 3) rate limit
- traefik.http.middlewares.api-rl.ratelimit.average=50
- traefik.http.middlewares.api-rl.ratelimit.burst=100

# attach two middlewares to a router
- traefik.http.routers.api.middlewares=sec-headers,api-rl

Note the doubled $$ in the basic-auth string: Compose interpolates a single $, so you escape it. Generate the hash with htpasswd -nb admin yourPassword.

Need a Traefik or Kubernetes review?

We’ll audit your reverse-proxy and ingress setup, fix the silent misconfigurations, and leave you with a runbook. Useful before any production launch or migration.

Book a 30-min review → WhatsApp → Email us →

Wildcard certificates with DNS-01

For multi-tenant SaaS where every customer gets a subdomain (acme.example.com, tenant42.example.com), you don’t want a separate certificate per tenant. Use one wildcard via the DNS-01 challenge. Figure 4 is the difference in one picture, and it’s also a rate-limit story we’ll come back to.

Traefik TLS: HTTP-01 issues one cert per host; DNS-01 issues one wildcard for all tenant subdomains, exempt via ARI

Figure 4. HTTP-01 issues one certificate per hostname; DNS-01 issues a single wildcard for every subdomain.

# traefik.yml — add a wildcard resolver
certificatesResolvers:
  wildcard-resolver:
    acme:
      email: ops@example.com
      storage: /letsencrypt/acme.json
      dnsChallenge:
        provider: cloudflare
        resolvers:
          - "1.1.1.1:53"
          - "8.8.8.8:53"
# docker-compose.yml — Cloudflare token + wildcard router
services:
  traefik:
    environment:
      - CF_DNS_API_TOKEN_FILE=/run/secrets/cf_token
    secrets:
      - cf_token

  api:
    labels:
      - traefik.enable=true
      - traefik.http.routers.api.rule=HostRegexp(`^[a-z0-9-]+\.example\.com$`)   # v3 uses Go regexp
      - traefik.http.routers.api.entrypoints=https
      - traefik.http.routers.api.tls.certresolver=wildcard-resolver
      - traefik.http.routers.api.tls.domains[0].main=example.com
      - traefik.http.routers.api.tls.domains[0].sans=*.example.com

secrets:
  cf_token:
    file: ./cloudflare-token.txt

Cloudflare, Route 53, GCloud DNS, DigitalOcean, OVH and a long list of others are supported. The full provider list is in the official Traefik ACME docs.

Reach for a DNS-01 wildcard when: you serve more than a handful of subdomains off one apex, or you onboard tenants faster than a per-host certificate flow can keep up. One *.example.com cert covers all of them and sidesteps the per-domain issuance ceiling.

Mini-case: wildcard TLS for a multi-tenant SaaS

We build and run multi-tenant platforms where every customer lives on their own subdomain. BrainCert, the online-learning platform we’ve worked on, runs 100K+ customers and 500M+ delivered classroom minutes on exactly that shape of infrastructure. Here is the reverse-proxy pattern, and the mistake we watch teams make.

Situation. A multi-tenant SaaS onboards each customer at tenant.app.example.com. The first instinct is one Let’s Encrypt certificate per tenant via HTTP-01. It works in a demo and it works for the first dozen customers.

The plan. Let’s Encrypt caps issuance at 50 certificates per registered domain per week. At roughly 40–50 tenants a burst of signups brushes that ceiling, issuance stalls, and new tenants land on TLS errors during onboarding — the worst possible first impression. So we switch to a single *.app.example.com wildcard via DNS-01 with a scoped Cloudflare token, and let ACME Renewal Information (ARI) drive renewals, which are exempt from the rate limits entirely.

Outcome. Certificate count drops from one-per-tenant to one, full stop. Onboarding a tenant becomes a DNS row and a container label, not a certificate request. And because every Traefik instance reads the same shared acme.json, a failover never shows a customer a certificate mismatch. Want a similar assessment of your edge? Grab a 30-minute call and bring your tenant model.

Migrating from Traefik v2 to v3

Traefik v3 is the version we run on new projects in 2026, and the migration from v2 is gentle. Your Docker labels mostly stay the same, and the routers/services/middlewares model is unchanged.

What changes: a small set of static-config renames, the plugin manifest format, and experimental flags promoted to GA (HTTP/3 among them). What stays the same: your labels, your ACME storage, your mental model. Read the official v2→v3 migration guide before you bump the image tag, and pin a specific patch release rather than a floating v3 tag.

Why upgrade: GA HTTP/3, native OpenTelemetry, WASM middleware, the Kubernetes Gateway API, and SPIFFE for workload identity. The performance ceiling is higher in v3 too.

HTTP/3 and QUIC, in two lines

Add http3: {} to your HTTPS entry point and open UDP 443. In v3 this is GA — the old experimental.http3 flag is gone. Browsers negotiate HTTP/3 automatically, and existing HTTP/1.1 and HTTP/2 clients keep working. Real-time video and edge-served apps benefit most, because QUIC tolerates packet loss without TCP’s head-of-line blocking. We default it on in front of the streaming stacks we build; if you’re new to that world, our Learn primer on digital video covers the fundamentals, and we use it on edge-AI surveillance and mobile streaming deployments.

Observability: logs, metrics, and OpenTelemetry

Three things we always wire in, all visible in Figure 3 as taps off the request path:

1. Access logs. JSON-formatted, shipped to Loki or CloudWatch. Request ID, latency, status, route name — the basics. Set accessLog.format: json.

2. Prometheus metrics. Enable metrics.prometheus and scrape /metrics. Watch traefik_router_request_duration_seconds_bucket for tail latencies per route.

3. OpenTelemetry traces (native in v3). Point Traefik at your OTLP collector and you get end-to-end traces from the edge through your services. A single OTLP target replaces the v2 Jaeger, Zipkin and Datadog drivers.

Traefik on Kubernetes: Ingress, IngressRoute, Gateway API

On Kubernetes the mental model is identical — only the provider changes. Traefik is the default ingress controller in k3s, shipped as an official Helm chart, which is why so many teams meet it there first. You have three ways to declare routes, and v3 speaks all of them.

1. Standard Ingress. The portable Kubernetes object. Works, but its annotations are limited — fine for simple host/path routing.

2. IngressRoute (Traefik CRD). Traefik’s own custom resource. This is where middlewares, TLS options and priorities live cleanly; it’s the day-to-day choice on Traefik-run clusters.

3. Kubernetes Gateway API. The vendor-neutral successor to Ingress. Traefik v3 tracks it closely (Gateway API v1.3 landed by v3.5). In k3s you enable it with a HelmChartConfig that sets providers.kubernetesGateway.enabled=true. If you want portability across ingress vendors, start here.

Reach for the Gateway API when: you want route definitions that survive a change of ingress controller, or you need the cleaner role split between cluster operators and app teams. Stick with IngressRoute when you’re all-in on Traefik and want its full middleware surface today.

Scaling Traefik beyond a single host

Single-host Traefik is fine up to roughly 10–30k rps depending on hardware and TLS load. Beyond that, you grow in the three stages shown in Figure 5.

Scaling Traefik: single host, then multiple instances with shared ACME behind an L4 load balancer, then Kubernetes

Figure 5. Three stages as traffic grows: shared ACME storage is what keeps multi-instance and cluster setups honest.

Run multiple Traefik instances behind a Layer-4 load balancer (HAProxy, AWS NLB) with shared ACME storage, or run Traefik as the cluster ingress on Kubernetes. We default to the K8s path on clusters and the multi-instance path on Compose fleets. We covered scale architecture more broadly in our scalable VMS guide.

A decision framework in five questions

When a team asks us to sign off on a proxy choice, we run these five questions. The answers usually settle it in a meeting.

1. How often do your services change? Daily deploys, preview environments, or tenants coming and going push you toward Traefik’s automatic discovery. A front-end that ships monthly does not.

2. What is your real peak RPS per core? Under ~10k, the proxy is not your bottleneck — optimize for operations. Above it, weigh NGINX or HAProxy for raw throughput.

3. How many TLS hostnames, and how fast do they grow? A few stable domains: HTTP-01 is fine. Many subdomains or fast tenant growth: DNS-01 wildcard, every time.

4. Docker, Kubernetes, or bare VMs? On K8s, Traefik or the Gateway API is a natural fit. On bare VMs with a static topology, a hand-tuned NGINX may be simpler to reason about.

5. Who owns the proxy at 3 a.m.? If no one owns on-call for a self-hosted edge, a managed option or a partner who runs it matters more than any feature checkbox. That is often where we come in.

Cost and effort to wire Traefik into a real product

Scope Effort Typical cost (Fora Soft) Outcome
Bootstrap config + dashboard 1–2 days $0.5–1.5k Working reverse proxy + Let’s Encrypt
Wildcard certs + multi-tenant routing 2–4 days $1–3k Tenant-subdomain SaaS ready
Security hardening + socket proxy + WAF 2–5 days $1.5–4k Hardened edge with rate limit + CSP
Observability (Prometheus, OTel) 3–5 days $2–5k Latency dashboards + tracing
Migration from NGINX or v2→v3 1–2 weeks $5–15k Zero-downtime cutover

Our quotes land below legacy SI vendors for the same scope because we use Agent Engineering to compress the rote configuration and audit work. The hard parts — security review, ACME edge cases, observability wiring — still take human attention, and that’s what our custom software development team focuses on.

Five Traefik pitfalls we see most often

1. Exposing the raw Docker socket. Mounting /var/run/docker.sock gives Traefik root-equivalent access to the host; if the container is ever compromised, so is the box. Put a read-only socket proxy in front, run Traefik non-root, and never expose the socket over the network.

2. Leaving the dashboard public. api.insecure: true on a public port reveals every route and certificate. Bind it to 127.0.0.1 or hide it behind basic-auth plus an IP allowlist.

3. Not persisting acme.json. Without a mounted /letsencrypt volume, every restart re-issues certificates and you burn the rate limit. Mount it and chmod 600.

4. Routing collisions across stacks. Two services with the same Host() rule fight non-deterministically. Use unique router names and explicit priority labels when rules overlap.

5. Running an unpatched image. 2025 brought real CVEs, including one where a TLS verify=on flag silently stopped verifying (CVE-2025-66491, fixed in v3.6.3) and a path-manipulation middleware bypass (CVE-2025-32431). Pin a patched release and watch the security advisories.

When you should NOT pick Traefik

Three honest cases. 1. A single-tenant, low-churn front-end where you already run NGINX and the team knows it — the migration cost will exceed the operational gain. 2. Extreme RPS at a single edge box, where NGINX or HAProxy still win on raw throughput. 3. Environments where you cannot grant the Docker socket or the Kubernetes API access Traefik needs — strictly air-gapped or zero-trust shops sometimes hit this. If any of these is you, we’ll say so.

FAQ

What is Traefik used for?

Traefik is a cloud-native reverse proxy and HTTP load balancer. It integrates with Docker, Kubernetes, Consul, ECS and Nomad, auto-discovers services, terminates TLS via Let’s Encrypt, runs middlewares (auth, rate limit, headers), and exposes a dashboard, Prometheus metrics and OpenTelemetry traces.

Traefik vs NGINX — which is better in 2026?

NGINX wins on raw throughput; Traefik wins on operational simplicity for container-rich workloads. If your services churn (microservices, preview envs, multi-tenant SaaS), Traefik saves real time each week. If your edge is a static front-end at high RPS, NGINX is still the right answer.

What is the latest version of Traefik?

Traefik v3 has been generally available since April 2024, and the current stable line in 2026 is v3.7 (v3.7.10 was released in July 2026). Start new projects on v3 and pin a specific patch release rather than a floating tag.

Does Traefik support free TLS certificates?

Yes. ACME / Let’s Encrypt is built in: HTTP-01 for single domains, DNS-01 for wildcards (Cloudflare, Route 53, GCloud DNS, DigitalOcean and more). Persist acme.json on a volume so you don’t hit issuance rate limits.

How do I get a wildcard certificate in Traefik?

Use a DNS-01 resolver with a supported DNS provider and set tls.domains[0].sans=*.example.com on the router. DNS-01 is the only challenge that can prove control of a wildcard, and one *.example.com cert then covers every subdomain.

Is Traefik the default ingress in Kubernetes?

It’s the default ingress controller in k3s, shipped as a Helm chart. On full Kubernetes you install it yourself. Traefik v3 supports standard Ingress, its own IngressRoute CRD, and the Kubernetes Gateway API, which you enable in k3s via a HelmChartConfig.

Can Traefik handle WebSocket and HTTP/3 traffic?

Yes. WebSocket upgrades pass through transparently, and HTTP/3 / QUIC is a one-line entry-point flag that’s GA in v3. We run it as the edge in front of WebRTC signaling and HLS endpoints across our streaming projects.

Is Traefik safe to put on the public internet?

Yes, if you keep the dashboard private, front the Docker socket with a read-only proxy, attach security-headers and rate-limit middlewares, keep the image patched, and consider a CDN/WAF (Cloudflare, AWS WAF) for L7 attack mitigation. Traefik is designed for that role.

Stack

Agora.io Alternative in 2026

Custom WebRTC behind Traefik — when the math beats CPaaS.

Stack

Twilio Video Alternatives

When and how to replace a CPaaS with custom infra.

Engineering

Scalable Video Management Systems in 2026

Where Traefik fits in a horizontally scalable VMS.

Architecture

Edge AI vs Cloud AI for Video Surveillance

Latency math that drives HTTP/3 and edge proxy choices.

Mobile

Optimize Android Apps for Smooth Video Streaming

QUIC, HTTP/3, ABR — what your edge proxy should support.

Need a backend, DevOps or video-infra partner who ships?

Traefik is a small piece of the picture. The harder questions are usually service decomposition, observability, secret management, real-time streaming, and what belongs on the edge. Those are the questions we answer for clients across SaaS, surveillance, edutainment and creator monetization.

If you want a quick second opinion on your reverse-proxy and ingress setup, or a partner to build the backend behind it, the fastest start is a 30-minute call with our engineering lead.

Let’s talk about your edge

Bring your topology and your traffic numbers. We’ll bring 20 years of real-time video and SaaS delivery and a quote we can defend.

Book a 30-min call → WhatsApp → Email us →

  • Technologies