Architecture & Request Flow
The Request Lifecycle
Understanding how Traefik processes a request is fundamental to configuring it correctly. The flow is:
- Client sends request to Traefik's EntryPoint (e.g.
:443) - EntryPoint receives the connection and forwards it to matching Routers
- Router evaluates rules (Host, Path, Headers, etc.) to find a match
- Router passes the request through a Middleware chain (if configured)
- Service receives the modified request and forwards it to a backend server
- Response flows back through the same path
Remember
Routers do NOT forward requests directly to services. The request passes through the middleware chain first, and only then reaches the service.
Configuration Model
Traefik has two layers of configuration:
Static Configuration
Set at startup via:
- CLI flags (
--entrypoints.web.address=:80) - Config file (
traefik.ymlortraefik.toml)
Static config defines:
- EntryPoints
- Providers
- TLS certificates resolvers (ACME)
- Observability settings (metrics, logs, tracing)
- API/dashboard settings
# traefik.yml — Static Configuration
api:
dashboard: true
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
certificatesResolvers:
letsencrypt:
acme:
email: admin@example.com
storage: /letsencrypt/acme.json
httpChallenge:
entryPoint: webDynamic Configuration
Updated at runtime via Providers (Docker labels, Kubernetes CRDs, Consul KV, file, etc.).
Dynamic config defines:
- Routers and their rules
- Services and load balancer settings
- Middleware chains
- TLS options
# Dynamic configuration via Docker labels
services:
web:
image: nginx
labels:
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`example.com`)"
- "traefik.http.services.web.loadbalancer.server.port=80"The separation between static and dynamic config is one of Traefik's most important design decisions. Static config rarely changes; dynamic config can change as often as containers start and stop.
Providers
Providers are Traefik's bridge to your infrastructure. They watch for changes and dynamically update the routing configuration.
| Provider | Type | Best For |
|---|---|---|
| Docker | Orchestrator | Single-server Docker deployments |
| Kubernetes | Orchestrator | K8s-native routing with CRDs or Ingress |
| Consul | KV Store | Service mesh / Consul-based infra |
| etcd | KV Store | etcd-based environments |
| ZooKeeper | KV Store | ZooKeeper-based environments |
| File | File | General purpose / testing |
| Marathon | Orchestrator | Marathon/Mesos deployments |
| Rancher | Orchestrator | Rancher-based environments |
| Redis | KV Store | Redis-based dynamic config |
| HTTP | External | Custom / dynamic API-based config |
| Nomad | Orchestrator | HashiCorp Nomad environments |
Provider Uniqueness
Each router, service, and middleware name must be unique across all providers. If both Docker and File providers define a router named "api", Traefik will error.
Router Rule Matching
Routers use matchers to decide which requests they handle:
http:
routers:
blog:
rule: "Host(`blog.example.com`) && PathPrefix(`/posts`)"
service: blog-serviceAvailable Matchers
| Matcher | Example | Description |
|---|---|---|
Host() | Host(\example.com`)` | Match request host |
HostRegexp() | HostRegexp( + regex pattern | Regex host matching |
Path() | Path(\/api`)` | Exact path match |
PathPrefix() | PathPrefix(\/api`)` | Path prefix match |
Method() | Method(\GET`, `POST`)` | HTTP method |
Header() | Header(\X-Api-Key`, `secret`)` | Request header match |
HeaderRegexp() | HeaderRegexp(\X-Version`, `v\d+`)` | Regex header match |
Query() | Query(\page`, `1`)` | Query parameter match |
ClientIP() | ClientIP(\10.0.0.0/8`)` | Source IP match (v3.0+) |
Headers() | Headers(\Content-Type`, `application/json`)` | Multiple headers |
Combining Rules
Use && (AND) and || (OR) to combine matchers:
# Host AND Path
rule: "Host(`api.example.com`) && PathPrefix(`/v2`)"
# Host OR Host
rule: "Host(`example.com`) || Host(`www.example.com`)"
# Complex conditions
rule: "(Host(`api.example.com`) || Host(`api.internal`)) && PathPrefix(`/graphql`) && Header(`X-GraphQL`, `true`)"Router Priority
When multiple routers match the same request, Traefik uses priority to decide:
routers:
api-v2:
rule: "Host(`api.example.com`) && PathPrefix(`/v2`)"
priority: 10
service: api-v2
api:
rule: "Host(`api.example.com`)"
service: apiPriority Rules
- Higher number = higher priority
- If no priority is set, the longest rule wins (by character count)
- Explicit priority always wins over rule-length comparison
- If priorities are equal and rules have the same length, the first router discovered wins
Next Steps
Now that you understand the architecture, let's dive into EntryPoints.