Traefik Labels: A Practical Reference

Traefik configuration via Docker labels, demystified — routers, services, middlewares, and TLS resolvers with copy-paste examples.

·2 min read
traefikdockerhomelab

Traefik’s label-based configuration is powerful but terse. The official docs are comprehensive; this post is the cheat sheet I wish I’d had when I started.

The Mental Model

Three concepts:

  • Routers match incoming requests (by Host, Path, etc.) and route them.
  • Services forward traffic to a backend container’s port.
  • Middlewares transform requests/responses on the way through.

Every label is namespaced under one of these. The pattern is:

traefik.<http>.<routers|services|middlewares>.<name>.<option>=<value>

A Minimal HTTPS Service

labels:
  - "traefik.enable=true"
  - "traefik.docker.network=traefik"
  - "traefik.http.routers.myapp.rule=Host(`app.example.com`)"
  - "traefik.http.routers.myapp.entrypoints=websecure"
  - "traefik.http.routers.myapp.tls.certresolver=le"
  - "traefik.http.services.myapp.loadbalancer.server.port=8080"
networks:
  traefik:
    external: true

That’s the irreducible HTTPS service. Six lines of labels, one network, one port. Don’t add anything else until you need it.

Entrypoints and Cert Resolvers

websecure is conventionally the HTTPS entrypoint (port 443). le is typically a Let’s Encrypt ACME resolver defined in Traefik’s static config. If you’re using a self-signed cert for development, drop the certresolver line and add tls: true to the router instead.

Middlewares: Compose, Don’t Duplicate

Middlewares are reusable. Define a CORS middleware once and reference it from many routers:

- "traefik.http.middlewares.cors.headers.accessControlAllowOriginList=https://app.example.com"
- "traefik.http.middlewares.cors.headers.accessControlAllowMethods=GET,POST,PUT"
- "traefik.http.middlewares.cors.headers.addVaryHeader=true"

Attach it with a comma-separated list:

- "traefik.http.routers.myapp.middlewares=cors@docker"

The @docker suffix disambiguates the source provider. It’s optional in most setups but makes logs easier to read.

Common Pitfalls

Forgetting the network. Traefik can only route to containers on a network it shares. The traefik.docker.network label tells Traefik which network to use when multiple are attached.

Priority confusion. When two routers could match the same request (overlapping Host rules), Traefik sorts by rule length by default. Use an explicit priority label when you need to override that.

Internal-only services. Set traefik.docker.network carefully and use traefik.enable=false on services you don’t want exposed at all — it’s safer than relying on network isolation.

Verifying Your Config

docker logs traefik will tell you which routers it discovered. The Traefik dashboard (if you’ve enabled it) shows the full configuration tree. When labels aren’t working, the answer is almost always in one of those two places.

That’s the workflow: label the container, attach the network, watch the logs. Everything else is middlewares.