This episode goes deeper into Traefik routers and rules: rule syntax, all matchers such as Host, HostRegexp, Path, PathPrefix, Method, Headers, and Query, the AND, OR, and NOT logical operators, complex rule examples, and automatic and manual priority rules for resolving routing conflicts.

The router is Traefik's decision-making unit, and rules are its language. Episode 6 teaches you to speak that language fluently: all available matchers, how to combine them with logical operators, and how Traefik decides which router wins when several rules overlap.
Mastery of rules is the skill that most often separates fragile Traefik configurations from robust ones. Many production incidents start with a rule that is too loose or a wrong priority. Let us build the right foundation from the start.
A router consists of a name, a rule, the entrypoint it serves, the destination service, and optional middlewares. The syntax is consistent whether through Docker labels or the file provider:
services:
web:
image: nginx:alpine
labels:
- traefik.enable=true
- traefik.http.routers.web.rule=Host(`web.localhost`)
- traefik.http.routers.web.entrypoints=web
- traefik.http.routers.web.service=web-svc
- traefik.http.routers.web.middlewares=compress
- traefik.http.services.web-svc.loadbalancer.server.port=80All router parts can be identified from traefik.http.routers.web.*. The file provider version will look identical with a more explicit YAML structure — we will see it in episode 19.
Host(app.example.com): matches the host name exactly.Host(example.com, www.example.com): accepts several hosts in one rule.HostRegexp({subdomain:[a-z]+}.example.com) — the {name:pattern} form is a named capture.Path(/api): matches only the exact path /api.Path(/api, /v2/api): accepts a list of paths.PathPrefix(/api): matches /api, /api/users, and so on — the most commonly used.Method(GET, POST): restricts HTTP methods.Headers(X-Token, abc123): matches a specific header value.Query(page, 1): matches a specific query parameter.All these matchers can be used in a single rule with logical operators. Traefik evaluates rules with matchers that map to real requests — the evaluation speed difference is practically unnoticeable.
Traefik supports three operators:
&& for AND: all conditions must be satisfied.|| for OR: one condition is enough.! for NOT: inverts a condition's result.() to group evaluation priority.Examples of correct and incorrect operator usage:
Host(`api.localhost`) && PathPrefix(`/v1`)
Host(`a.localhost`) || Host(`b.localhost`)
Host(`admin.localhost`) && !PathPrefix(`/public`)
(Host(`api.localhost`) && PathPrefix(`/v1`)) || Path(`/ping`)Note that operators are written between matchers, not inside them. The syntax inside a matcher's backticks does not accept operators — for example Host(a.localhost || b.localhost) is wrong. A Host matcher that wants to accept multiple domains lists them with commas, not the OR operator.
Here are patterns often used in the field:
services:
app:
image: myapp:latest
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=(Host(`app.example.com`) || Host(`app.internal`)) && PathPrefix(`/`)
- traefik.http.routers.app.entrypoints=web
- traefik.http.routers.app.service=app-svc
- traefik.http.services.app-svc.loadbalancer.server.port=8080
admin:
image: myadmin:latest
labels:
- traefik.enable=true
- traefik.http.routers.admin.rule=Host(`admin.example.com`) && Headers(`X-Admin`, `true`)
- traefik.http.routers.admin.entrypoints=web
- traefik.http.routers.admin.service=admin-svc
- traefik.http.services.admin-svc.loadbalancer.server.port=9000The app router serves two domains at once, while the admin router is only active if the host is correct and the X-Admin header equals true. Combinations like this allow the same service to be routed differently for different user segments.
When two routers have rules that both match, Traefik chooses based on priority. Automatically, priority is calculated from the number of characters in the rule: the more specific (longer) rule wins. Example: PathPrefix(/api/v2) automatically wins over PathPrefix(/api).
However, sometimes the automatic calculation does not match expectations. You can override it with the priority label — below we set the traefik.http.routers.special.priority label to a manual value:
labels:
- traefik.enable=true
- traefik.http.routers.special.rule=PathPrefix(`/api/v2`)
- traefik.http.routers.special.priority=100
- traefik.http.routers.special.service=special-svc
- traefik.http.services.special-svc.loadbalancer.server.port=3000The rule above wins over other /api routers regardless of their rule length, as long as both match. Manual priority is the clearest way to control conflicts — use it consistently so you do not confuse your team.
Tip
When two routers match and have the same priority, Traefik picks based on the alphabetical order of router names. Never rely on this behavior — always set priority explicitly for overlapping routes.
Key takeaways:
&&, ||, !, and parentheses combine multiple conditions.priority.In episode 7 next we will cover services & load balancing — HTTP, TCP, and UDP service types, server definitions, weight distribution, sticky sessions, health checks, load balancing algorithms, and service mirroring for traffic shadowing and canary deployments.