LW IT Solutions
« Blog Overview /IT & Networks / Traefik Labels in Detail, Including the Dollar...

Traefik Labels in Detail, Including the Dollar Trap

Traefik Labels in Detail, Including the Dollar Trap
Contents
  1. Three Objects, One Name
  2. The Provider Suffix
  3. The Dollar Trap
  4. What Each Mistake Looks Like from Outside
  5. Two Habits That Prevent Most of It
  6. Sources

Traefik is configured by writing labels on a container, which sounds like a list of settings and is really a namespace. The keys are paths through a tree, and what looks like six independent lines is three objects that only know about each other because a segment in the middle of the key happens to be spelled the same.

That construction is what makes the configuration short and what makes its failures quiet. Nothing validates a name against anything, so a mistake produces a second, empty object rather than a complaint.

The Traefik label namespace as a tree with routers, middlewares and services, the shared name highlighted in three places and the doubled dollar signs marked
The keys are a tree. The name in the middle is the only thing tying the three branches together.

Three Objects, One Name

A router decides which requests belong to this container, a service says where to send them, and a middleware modifies them on the way. Each lives under its own branch of traefik.http, and each is identified by a name that is chosen freely – the label key is the declaration.

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.blog.rule=Host(`blog.example.com`)"
  - "traefik.http.routers.blog.entrypoints=websecure"
  - "traefik.http.routers.blog.tls.certresolver=le"
  - "traefik.http.routers.blog.middlewares=blog-auth@docker"
  - "traefik.http.middlewares.blog-auth.basicauth.users=admin:$$2y$$05$$e6zX…"
  - "traefik.http.services.blog.loadbalancer.server.port=8080"

The router and the service are bound because both are called blog. There is no line that says so. Writing traefik.http.services.blogg.loadbalancer.server.port creates a service named blogg that nothing points at, and a router named blog that has no service – and Traefik will answer requests for that host with a 404 rather than say what is missing.

When the container exposes exactly one port, the service label can be left out entirely and Traefik infers it. That convenience is worth knowing about mostly so it can be recognised in someone else’s file – as soon as a second port appears, the inference stops and the route breaks at the moment an unrelated port is added.

The Provider Suffix

Middlewares are referenced by name, and the name is not enough. Traefik keeps a separate namespace per provider – the Docker labels, a static file, a Kubernetes resource. A bare blog-auth is looked up in the provider that is asking, with a fallback that surprises people often enough to be worth stating: the reference belongs written as blog-auth@docker.

Getting it wrong is the quietest failure of the three. The router is valid, the service is valid, the route works – it simply serves the application without the authentication that was supposed to sit in front of it. Nothing in the log says a middleware was skipped, because from Traefik’s point of view none was requested.

The Dollar Trap

A bcrypt hash looks like $2y$05$e6zX... and consists largely of dollar signs. Docker Compose performs variable substitution on every value it reads, so $2y becomes an empty string, $05 becomes an empty string, and the password that reaches Traefik is a fragment that matches nothing.

# generate
htpasswd -nbB admin "passwort"
admin:$2y$05$e6zXx8Q0m2yYy1H4o1Yb1uJf2Rr7cKq5dW6vT8sN0pL3aG9hC1dS2

# in docker-compose.yml every $ is doubled
admin:$$2y$$05$$e6zXx8Q0m2yYy1H4o1Yb1uJf2Rr7cKq5dW6vT8sN0pL3aG9hC1dS2

# in a plain labels file or on the command line it stays single

The doubling is a Compose rule, not a Traefik rule, which is why the same string has to be written differently depending on where it lives. A hash placed in Traefik’s own dynamic configuration file keeps its single dollars; the same hash in a compose file needs them doubled; and moving a working configuration from one to the other breaks it in exactly this way.

The symptom is a login prompt that refuses every password, including the right one, which sends people to check the password rather than the file that ate it.

What Each Mistake Looks Like from Outside

Mistake Symptom Where to look
Name differs between router and service 404 for that host the dashboard: a router with no service
Middleware without @docker the site opens without authentication the dashboard: the router lists no middleware
Single dollar signs in compose 401 for every password docker inspect: the label is shorter than the hash
Container not on the proxy network 502 or 504 the service has no reachable server
traefik.enable=true missing 404, nothing appears at all the dashboard: the container is not listed
Two containers, same router name one of them wins, apparently at random the dashboard: one router, one backend

Five of the six are answered by the dashboard, which is the argument for enabling it on an internal entrypoint even on a small machine. It shows what Traefik actually understood, and every one of these mistakes is a difference between what was written and what was understood.

Two Habits That Prevent Most of It

The first is to derive every name from the service and use it unchanged in all three places – container blog, router blog, service blog, middleware blog-auth. A name that is mechanical cannot be misremembered, and a diff between two containers’ labels then shows only the lines that genuinely differ.

The second is to read the labels back rather than the file. docker inspect shows the values as the daemon stored them, after Compose has finished substituting – which is where a doubled dollar becomes a single one again, and where a hash that survived is visibly the same length as the one that was generated.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Write a comment

The email address is not published. Required fields are marked with an asterisk.

ALL ARTICLES & CATEGORIES

CCTV

Follow this category by RSS

Cloud & AI

Follow this category by RSS

Data Privacy

All 12 articles in this category Follow this category by RSS

Digital Analytics

All 47 articles in this category Follow this category by RSS

Digital Marketing

All 25 articles in this category Follow this category by RSS

IT & Networks

All 16 articles in this category Follow this category by RSS

Raspberry PI

Follow this category by RSS

Smart Home

All 14 articles in this category Follow this category by RSS

Web Development

Follow this category by RSS

WordPress Plugins & Tricks

Follow this category by RSS