Using Traefik’s Built‑In Rate‑Limiting Middleware to Shield Services from Traffic Spikes
Configure Traefik’s built‑in rate‑limit middleware to guard services from traffic spikes, with a Docker‑compose example, memory trade‑offs, and verification steps.
12 Jun 2026, 09:13 UTC

Problem: Unprotected services buckle under sudden traffic
When an HTTP service is exposed directly to the internet, a burst of requests—or a misbehaving client—can consume CPU, memory, or connection pools faster than the backend can handle. The result is increased latency, failed requests, and a degraded experience for legitimate users. Operators need a lightweight, declarative way to throttle traffic at the edge before it reaches the application.
Thesis: Traefik’s native rate‑limiting middleware offers a simple, configurable token‑bucket limiter that works across HTTP, TCP and UDP routers, with optional Redis backing for distributed deployments.
How the middleware works
Traefik implements the token‑bucket algorithm: each client (by default identified by its IP address) receives a bucket that refills at a steady rate. A request consumes a token; if the bucket is empty, the request is rejected with HTTP 429 (Too Many Requests). The middleware can be declared once and referenced by any router, making it easy to apply consistently.
Key labels (or static configuration keys) are:
traefik.http.middlewares..ratelimit.rate– average requests per period allowedtraefik.http.middlewares..ratelimit.period– time window for the rate (e.g.,1s)traefik.http.middlewares..ratelimit.burst– optional extra tokens for short spikes
By default the counters live in Traefik’s memory. This works well for a single instance but can cause high RAM usage when the key space is large (e.g., per‑IP limiting with many distinct clients). For multi‑node setups you must switch to a Redis store to share state, which adds an operational dependency.
Worked example: limiting a web service to 100 req/s per client IP
Assume a Docker‑compose file that runs Traefik v2.9+ and a simple web container called whoami. The steps below add a middleware named ip-limit and attach it to the router for whoami.
version: '3.8'
services:
traefik:
image: traefik:v2.11
command:
- '--api.insecure=true'
- '--providers.docker=true'
- '--entrypoints.web.address=:80'
ports:
- '80:80'
- '8080:8080' # dashboard
volumes:
- '/var/run/docker.sock:/var/run/docker.sock:ro'
whoami:
image: traefik/whoami
labels:
- 'traefik.enable=true'
- 'traefik.http.routers.whoami.rule=Host(`whoami.localhost`)'
- 'traefik.http.routers.whoami.entrypoints=web'
# --- rate‑limit middleware definition ---
- 'traefik.http.middlewares.ip-limit.ratelimit.rate=100'
- 'traefik.http.middlewares.ip-limit.ratelimit.period=1s'
# optional burst of 20 tokens
- 'traefik.http.middlewares.ip-limit.ratelimit.burst=20'
# attach middleware to router
- 'traefik.http.routers.whoami.middlewares=ip-limit'
Where to run: execute docker compose up -d on a host with Docker Engine and sufficient privileges to bind ports 80 and 8080. No additional permissions are needed beyond Docker access.
Verifying the limiter is active
After the stack is up, generate traffic from a single client IP (e.g., using hey -z 10s -c 50 http://whoami.localhost/). You should see:
- Responses with status 200 up to the allowed rate.
- Responses with status 429 once the bucket is exhausted.
To confirm without relying on response codes, inspect Traefik’s logs (accessed via docker logs <traefik-container-id>) for lines containing rate limit exceeded. The presence of such lines indicates the middleware is evaluating and rejecting requests.
If you opt for a Redis‑backed store (recommended for >1 Traefik replica), add the following labels to the middleware definition:
traefik.http.middlewares.ip-limit.ratelimit.redis.address=redis:6379
traefik.http.middlewares.ip-limit.ratelimit.redis.password=__redis_password__
traefik.http.middlewares.ip-limit.ratelimit.redis.duration=1h
Run Redis in the same network, then check with redis-cli monitor while traffic flows; you should see INCR commands on keys matching the pattern traefik_ratelimit_*. This confirms state is being shared.
Trade‑offs and limitations
Memory usage – With the default in‑memory store, each distinct client IP creates a counter. In a high‑cardinality scenario (e.g., public internet with thousands of IPs) RAM can grow linearly. Mitigation strategies include:
- Using a broader key (e.g., per‑API‑key or per‑subnet) to reduce cardinality.
- Switching to Redis, which offloads storage but introduces an extra component and potential latency.
Scope of protection – The token‑bucket limiter guards against volumetric abuse but does not stop slow‑loris attacks, malformed payloads, or application‑level logic flaws. Pair it with other middlewares such as requestsize (to cap body size) or retry (to manage transient failures) for defense‑in‑depth.
Configuration drift – Because the middleware is defined via labels, a change to the Docker‑compose file requires a stack restart. Treat the labels as part of your service’s declarative configuration and version‑control them alongside the application code.
Actionable closing
Start small: apply the rate‑limit middleware to a non‑critical endpoint with a modest rate (e.g., 10 req/s). Observe the Traefik dashboard or logs for 429 responses, then gradually increase the limit until it matches your service’s measured capacity. Monitor both response latency and Redis memory (if used) to ensure the limiter stays effective without becoming a bottleneck. This incremental approach lets you protect your services from traffic spikes while keeping operational overhead visible and manageable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.