Traefik

Traefik is an open-source reverse proxy and load balancer designed for modern cloud-native applications—especially those running in containers.


What that actually means

Think of Traefik as a smart traffic controller sitting in front of your apps:

  • It receives incoming requests (like someone visiting your website)
  • Then routes them to the correct service (e.g., your API, frontend, or another container)
  • It can also balance traffic across multiple instances of the same service

Key features

Automatic service discovery

Image
Image

Traefik integrates directly with tools like:

  • Docker
  • Kubernetes

It automatically detects new containers/services and routes traffic to them—no manual config needed.


Built-in HTTPS (SSL/TLS)

  • Automatically generates and renews certificates using Let’s Encrypt
  • Handles HTTPS setup for you (no manual certificate management)

Load balancing

  • Distributes requests across multiple instances
  • Helps keep your app fast and available

Dynamic configuration

  • Updates routes in real time when services start/stop
  • No restarts required

Dashboard & monitoring

  • Web UI shows routes, services, and traffic
  • Useful for debugging and observability

Simple example (Docker)

If you run a container with labels like:

labels:
- "traefik.http.routers.myapp.rule=Host(`myapp.local`)"

Traefik will:

  • Detect the container
  • Create a route for myapp.local
  • Start sending traffic there automatically

When people use Traefik

  • Microservices architectures
  • Docker or Kubernetes setups
  • Hosting multiple apps on one server
  • Replacing tools like:
    • NGINX
    • HAProxy

In one sentence

Traefik is a modern, automatic reverse proxy that makes routing traffic to containerized apps simple and dynamic.


Here’s a small working Docker Compose example you can run locally. It follows Traefik’s current Docker quick-start pattern: Traefik listens to Docker, exposes port 80 for app traffic and 8080 for the dashboard, and routes a sample whoami container using labels. (Traefik Docs)

version: "3.9"
services:
traefik:
image: traefik:v3.0
container_name: traefik
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entryPoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: traefik/whoami
container_name: whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.localhost`)"
- "traefik.http.routers.whoami.entrypoints=web"

Run it with:

docker compose up -d

Then open:

  • http://whoami.localhost → sample app
  • http://localhost:8080 → Traefik dashboard

That hostname rule is the key idea: Traefik reads the Docker labels and creates a router so requests for whoami.localhost go to the whoami container. Traefik hot-reloads this dynamic routing config from Docker without restarting. (Traefik Docs)

How to read the important lines:

  • --providers.docker=true tells Traefik to watch Docker for containers/services. (Traefik Docs)
  • --providers.docker.exposedbydefault=false means only containers with traefik.enable=true get exposed. (Traefik Docs)
  • --entryPoints.web.address=:80 creates an HTTP entrypoint on port 80. (Traefik Docs)
  • traefik.http.routers.whoami.rule=Host(\whoami.localhost`)` matches incoming requests by hostname. (Traefik Docs)

A more realistic example is routing two apps:

version: "3.9"
services:
traefik:
image: traefik:v3.0
command:
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entryPoints.web.address=:80"
ports:
- "80:80"
- "8080:8080"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
app1:
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.app1.rule=Host(`app1.localhost`)"
- "traefik.http.routers.app1.entrypoints=web"
app2:
image: traefik/whoami
labels:
- "traefik.enable=true"
- "traefik.http.routers.app2.rule=Host(`app2.localhost`)"
- "traefik.http.routers.app2.entrypoints=web"

Then:

  • http://app1.localhost → app1
  • http://app2.localhost → app2

That is basically the Traefik workflow: define a service, add labels, and Traefik discovers it automatically. The official docs also note that when both containers are in the same Compose file, Docker’s default network is enough for Traefik to reach them. (Traefik Docs)

A couple of useful notes:

  • The dashboard setting shown here is insecure and meant for local learning, not production. (Traefik Docs)
  • For production, people usually add TLS/HTTPS and often Let’s Encrypt certificate automation through Traefik’s config. The routing and certificates are part of Traefik’s dynamic config model. (Traefik Docs)

Want me to show the same thing with HTTPS + Let’s Encrypt, or a Kubernetes Ingress example?

Here’s a real HTTPS + Let’s Encrypt Docker Compose setup for Traefik.

It uses the HTTP-01 challenge, which means your server must be publicly reachable on ports 80 and 443, and your domain’s DNS must point at that server. Traefik’s docs also note that certificate resolvers are defined in static config, the router must have TLS enabled, and the router references the resolver by name. (Traefik Docs)

version: "3.9"
services:
traefik:
image: traefik:v3.4
container_name: traefik
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
# entrypoints
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
# redirect http -> https
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
# lets encrypt
- "--certificatesresolvers.le.acme.email=you@example.com"
- "--certificatesresolvers.le.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.le.acme.httpchallenge=true"
- "--certificatesresolvers.le.acme.httpchallenge.entrypoint=web"
ports:
- "80:80"
- "443:443"
- "8080:8080" # optional dashboard
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
- "./letsencrypt:/letsencrypt"
app:
image: traefik/whoami
container_name: whoami
labels:
- "traefik.enable=true"
# router
- "traefik.http.routers.app.rule=Host(`whoami.yourdomain.com`)"
- "traefik.http.routers.app.entrypoints=websecure"
- "traefik.http.routers.app.tls=true"
- "traefik.http.routers.app.tls.certresolver=le"

Then run:

mkdir -p letsencrypt
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.json
docker compose up -d

Then open:

  • https://whoami.yourdomain.com
  • http://whoami.yourdomain.com will redirect to HTTPS

Why this works:

  • providers.docker=true makes Traefik watch Docker containers and labels. (Traefik Docs)
  • entrypoints.web and entrypoints.websecure create listeners on ports 80 and 443. (Traefik Docs)
  • certificatesresolvers.le.acme.* configures Let’s Encrypt and stores certs in acme.json. (Traefik Docs)
  • tls.certresolver=le tells that router to request and renew a cert through the le resolver. (Traefik Docs)

A couple of important gotchas:

  • Replace you@example.com with your real email.
  • Replace whoami.yourdomain.com with a real domain/subdomain you control.
  • That hostname needs an A or AAAA record pointing to your server. Traefik’s docs say ACME domains must point to Traefik. (Traefik Docs)
  • Port 8080 is just for the dashboard. Don’t leave it openly exposed on the internet unless you secure it. (Traefik Docs)

For Kubernetes, the usual Traefik-native route is an IngressRoute or standard Ingress; Traefik also documents a working Kubernetes + Let’s Encrypt example with CRDs. (Traefik Docs)

Leave a comment