Gateway Middlewares
1. Overview
Middlewares in Traefik process requests before they reach the backend service. BANA defines shared middlewares in packages/gateway/config/dynamic/middlewares.yml (file provider) and references them via Docker labels on each service with the @file suffix.
Source: packages/gateway/config/dynamic/middlewares.yml
2. Middleware Pipeline
3. Provider Namespacing
Traefik uses provider namespacing to distinguish where middlewares are defined:
| Suffix | Provider | Defined In |
|---|---|---|
@file | File provider | packages/gateway/config/dynamic/middlewares.yml |
@docker | Docker provider | Docker labels on the service container |
| (none) | Same provider | Only works within the same provider scope |
Since shared middlewares live in the file provider, Docker labels must use the @file suffix:
# Correct
- "traefik.http.routers.commerce.middlewares=rate-limit@file,circuit-breaker@file,security-headers@file"
# Wrong — Traefik looks for "rate-limit" in Docker provider (doesn't exist)
- "traefik.http.routers.commerce.middlewares=rate-limit,circuit-breaker,security-headers"4. Shared Middleware Definitions
All shared middlewares are defined in packages/gateway/config/dynamic/middlewares.yml.
Circuit Breaker
Trips when network error ratio exceeds 10% or P95 latency exceeds 3 seconds. After tripping, the circuit stays open for 15 seconds, then gradually recovers over 30 seconds. The 5xx-response-ratio term is present in source but commented out.
Source: packages/gateway/config/dynamic/middlewares.yml
http:
middlewares:
circuit-breaker:
circuitBreaker:
# 5xx-ratio term commented out in source:
# expression: "ResponseCodeRatio(500, 600, 0, 600) > 0.30 || NetworkErrorRatio() > 0.10 || LatencyAtQuantileMS(95.0) > 3000"
expression: "NetworkErrorRatio() > 0.10 || LatencyAtQuantileMS(95.0) > 3000"
checkPeriod: 5s
fallbackDuration: 15s
recoveryDuration: 30sStates:
- Closed — normal operation, requests pass through
- Open — all requests fail fast with 503 (triggered by expression). Lasts
fallbackDuration(15s). - Recovering — limited requests allowed to test recovery. Lasts up to
recoveryDuration(30s). Returns to Closed if healthy, re-opens if expression still triggers.
Rate Limiting (Global)
Source: middlewares.yml (lines 53–59)
Applied to most services — 200 requests/second per client IP:
rate-limit:
rateLimit:
average: 200
burst: 400
sourceCriterion:
ipStrategy:
depth: 1Rate Limiting (Auth)
Source: middlewares.yml (lines 62–69)
Stricter limit for authentication endpoints — 30 requests/minute per client IP:
rate-limit-auth:
rateLimit:
average: 30
burst: 60
period: 1m
sourceCriterion:
ipStrategy:
depth: 1sourceCriterion.ipStrategy.depth: 1 extracts the real client IP from the X-Forwarded-For header (required because Traefik sits behind Nginx).
Security Headers
Source: middlewares.yml (lines 72–79)
Hides server information and prevents common attacks:
security-headers:
headers:
browserXssFilter: true
contentTypeNosniff: true
frameDeny: true
customResponseHeaders:
Server: ""
X-Powered-By: ""| Header | Effect |
|---|---|
browserXssFilter: true | Adds X-XSS-Protection: 1; mode=block |
contentTypeNosniff: true | Adds X-Content-Type-Options: nosniff |
frameDeny: true | Adds X-Frame-Options: DENY |
Server: "" | Strips the Server response header |
X-Powered-By: "" | Strips the X-Powered-By response header |
Dashboard Authentication
Source: middlewares.yml (lines 36–39)
The Traefik dashboard is protected by HTTP Basic Auth (not exposed with api.insecure):
dashboard-auth:
basicAuth:
users:
- "nx.eventry:$apr1$V3YHNLtR$x1jWCQ8.AiEfXoEc4ko7M0"Redirect to Dashboard
Source: middlewares.yml (lines 30–34)
Redirects root path / to /dashboard/ on the traefik entrypoint:
redirect-to-dashboard:
redirectRegex:
regex: "^/$"
replacement: "/dashboard/"
permanent: false5. Dashboard Routers
Source: middlewares.yml (lines 8–23)
The dashboard is exposed via file provider routers on the traefik entrypoint (:8080 → host port 30100):
http:
routers:
dashboard:
rule: "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
entryPoints:
- traefik
service: api@internal
middlewares:
- dashboard-auth
dashboard-redirect:
rule: "Path(`/`)"
entryPoints:
- traefik
service: api@internal
middlewares:
- redirect-to-dashboard
- dashboard-auth| Router | Rule | Middlewares | Notes |
|---|---|---|---|
| dashboard | PathPrefix(/api) || PathPrefix(/dashboard) | dashboard-auth | Main dashboard + API routes |
| dashboard-redirect | Path(/) | redirect-to-dashboard, dashboard-auth | Root redirect to /dashboard/ |
6. Applying Middlewares to Services
Middlewares are applied via Docker labels on each service. The @file suffix is required:
# Standard service (commerce, sale, finance, etc.)
labels:
- "traefik.http.routers.commerce.middlewares=rate-limit@file,circuit-breaker@file,security-headers@file"
# Auth service (stricter rate limiting)
labels:
- "traefik.http.routers.identity.middlewares=rate-limit-auth@file,circuit-breaker@file,security-headers@file"7. Middleware Assignment per Service
| Service | Rate Limit | Circuit Breaker | Security Headers |
|---|---|---|---|
| identity | rate-limit-auth@file (30/min per-IP) | Yes | Yes |
| commerce | rate-limit@file (200/s per-IP) | Yes | Yes |
| sale | rate-limit@file (200/s per-IP) | Yes | Yes |
| finance | rate-limit@file (200/s per-IP) | Yes | Yes |
| inventory | rate-limit@file (200/s per-IP) | Yes | Yes |
| payment | rate-limit@file (200/s per-IP) | Yes | Yes |
| payment-webhook | — | — | security-headers@file |
| signal (REST) | rate-limit@file (200/s per-IP) | Yes | Yes |
| signal (WS) | — | — | — |
| portal | — | — | — (uses dashboard-auth@file for basic auth) |
8. Adding Custom Middlewares
Option A: File provider (shared across services)
- Define the middleware in
packages/gateway/config/dynamic/middlewares.yml - Reference it in Docker labels with
@filesuffix:yaml- "traefik.http.routers.<service>.middlewares=<middleware-name>@file,..." - Traefik auto-reloads file-based dynamic config (no restart needed)
Option B: Docker provider (per-service)
- Define the middleware directly in the service's Docker labels:yaml
- "traefik.http.middlewares.<middleware-name>.<type>.<setting>=<value>" - Reference it with
@dockersuffix (or no suffix from within Docker labels):yaml- "traefik.http.routers.<service>.middlewares=<middleware-name>@docker,..."
The payment webhook's replacepathregex middleware uses Option B since it is specific to that service.
9. Related Pages
| Document | Description |
|---|---|
| Gateway Overview | Identity card + service catalog |
| Architecture | C4 views, request-routing flows |
| Routing | Docker label routing, 3 routing patterns |
| Resilience | Circuit breaker states, health checks, retry |
| Configuration | Traefik/Nginx config, constants |
| Decisions | ADRs |