Rate Limiter
The Rate Limiter middleware enforces a fixed‑window rate limit on incoming requests. You configure a maximum number of requests allowed in a given time span, along with how to identify the client and where to store counters (in‑memory or Redis).
By default it limits per IP address using an in‑memory store, but you can:
- Change the window size (
requests
perseconds
) - Limit based on other attributes (header or query parameter)
- Swap to a Redis backend for cross‑process rate limiting
- Customize the error response when the limit is exceeded
Configuration
rate_limit \
requests: 100, # max 100 requests
seconds: 60, # per 60‑second window
key: "address", # limit by client IP
store_config: "in_memory", # use local in‑memory store
error_response: "too_many_requests"
requests
/ seconds
requests
: Number of allowed requests in each window (positive integer).seconds
: Length of each fixed window in seconds (positive integer).
key
How to identify the client:
"address"
(default): use the client’s socket IP.- Header or query parameter:
key: { parameter: { header: { name: "X-Api-Key-Id" } } }
key: { parameter: { query: { name: "user_id" } } }
store_config
Where to keep counters:
"in_memory"
(default): per‑process, reset when server restarts.- Redis (shared across workers):
store_config: { redis: { connection_url: "redis://localhost:6379/1" } }
error_response
Customizes the response when the limit is reached (default is built‑in too_many_requests
):
error_response: {
code: 429,
plaintext: { inline: "Rate limit exceeded" },
default: "plaintext"
}
Rate Limit Response Headers
When a request exceeds the allowed rate, the middleware returns your configured error response plus these headers:
Header | Meaning |
---|---|
X-RateLimit-Limit | The maximum number of requests allowed per window (requests value). |
X-RateLimit-Remaining | How many requests remain in the current window (will be 0 once the limit is hit). |
X-RateLimit-Reset | Seconds until the current window resets (time until your counter zeroes out). |
Retry-After | Same value as X-RateLimit-Reset — suggests when clients should retry their request. |
Example With
requests: 5, seconds: 60
, after 5 calls the 6th returns:429 Too Many Requests X-RateLimit-Limit: 5 X-RateLimit-Remaining: 0 X-RateLimit-Reset: 42 Retry-After: 42
How It Works
-
On each request
- Compute the client key (IP, header, or query).
- Increment a counter for the current time window.
-
Fixed‑window logic
- If the counter ≤
requests
, allow through. - Otherwise, immediately return the configured
error_response
plus the X-RateLimit headers.
- If the counter ≤
-
Store options
- In‑memory: simple hash, fast but not shared across processes.
- Redis: atomic
INCR
+EXPIRE
commands, shared across all workers.
Place rate_limit
anywhere in your routing DSL to apply it to all downstream handlers in that scope.
Trusted Proxies
By default, a rate limiter middleware uses the IP address from the underlying socket (remote_addr). However, if your server is behind a reverse proxy, all requests will appear to come from the proxy’s IP address. This can break IP-based rules or cause rate-limiting to group all users together.
To address this, you can declare trusted proxies and instruct the server to extract the original client IP from forwarded headers only if the request came from one of these proxies.
Configuring trusted_proxies
To trust one or more upstream proxies, provide a trusted_proxies map in the middleware configuration. E.g.
rate_limit \
requests: 100, # max 100 requests
seconds: 60, # per 60‑second window
key: "address", # limit by client IP
store_config: "in_memory", # use local in‑memory store
error_response: "too_many_requests",
trusted_proxies: {
"192.168.1.1" => { header: { name: "X-Forwarded-For" } }
}