Rate Limiting
Use this module when you need to protect upstream services by limiting request rates at the nginx layer.
When to use this module
- You want to cap requests per second by client IP.
- You need burst allowance so legitimate traffic spikes are not rejected.
- You want to vary the rate limit cost by request (e.g., expensive endpoints cost more tokens).
- You need to skip rate limiting for trusted or internal traffic.
- You want the rate limit decision and budget visible in logs or response headers.
nginx.conf synthesis
Rate limiting is configured per location. Basic usage just needs a rate:
location /api {
ratelimit_rate 10r/s;
proxy_pass http://backend;
}
Add burst to smooth out short traffic spikes:
location /api/heavy {
ratelimit_rate 5r/s;
ratelimit_burst 10;
proxy_pass http://backend;
}
Use variables to control cost, key, and skip dynamically:
location /expensive {
set $rl_cost 3;
set $rl_skip 0;
ratelimit_rate 10r/s;
ratelimit_cost $rl_cost;
ratelimit_skip $rl_skip;
add_header X-Ratelimit-Result $ratelimit_result always;
add_header X-Ratelimit-Key $ratelimit_key always;
proxy_pass http://backend;
}
Directive reference
ratelimit_rate
- Contexts:
location - Default: none
Sets the rate limit in requests per second. Accepts 10r/s or plain 10 syntax.
ratelimit_burst
- Contexts:
location - Default:
0
Allows additional burst requests beyond the base rate. Requests within the burst window are not rejected.
ratelimit_key
- Contexts:
location - Default: client IP address
Overrides the identity used for rate-limit accounting. Set this to a variable to key on a customer ID, API key, or any request attribute instead of the client IP.
ratelimit_cost
- Contexts:
location - Default:
1
Controls how many tokens a single request consumes. The variable should resolve to an integer. Invalid or missing values fall back to 1.
ratelimit_skip
- Contexts:
location - Default: disabled
Bypasses rate limit enforcement when the variable resolves to a truthy value (1, true, yes, on). Use this when an earlier access module signals a trusted request.
Variables
The module exports these nginx variables for observability:
| Variable | Description |
|---|---|
$ratelimit_result | Per-request decision: allow or deny |
$ratelimit_key | The effective key used for accounting on the current request |
$ratelimit_source | Where the key came from: ip or variable |
$ratelimit_cost | The effective token cost applied to the current request |
Behavior notes
- Uses a 1-second fixed window algorithm. Each key gets a counter that resets every second.
- Returns HTTP 429 (Too Many Requests) when the limit is exceeded.
- Rate state is stored in nginx shared memory, so the same budget is enforced across all workers.
- Up to 1024 unique keys are tracked in the shared zone. When full, the oldest entries are reused.
- Runs in the access phase. Earlier modules that return a final status (401, 403, 429) will prevent the rate limit decision from running.
- Counters are location-scoped. Changing
ratelimit_keychanges identity within that location, not across unrelated locations.
Works well with
- Stock nginx
limit_reqandlimit_conn— these handle request and connection limits; ratelimit adds variable-driven keys, cost weighting, and shared-memory counters. - Request ID for correlating rate-limited requests across logs.
- JWT Authentication or OpenID Connect when you want to rate limit by authenticated identity rather than IP address.
- Circuit Breaker for a second layer of protection when rate limits are not enough.