Rate Limiting and Connection Limits
Introduction
Public endpoints attract bots and accidental traffic spikes. Nginx can limit request rate and concurrent connections per IP before requests hit your Java or Node process. This chapter sets up limit_req and limit_conn for login and API paths—complement, not replacement, for app-level throttling.
Prerequisites
limit_req: Request Rate
Define a shared memory zone in http context:
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://127.0.0.1:8080/;
include /etc/nginx/proxy_params;
}
}
}Code explanation:
$binary_remote_addr— client IP as zone keyzone=api_limit:10m— store state in 10 MB shared memoryrate=10r/s— average 10 requests per second per IPburst=20— allow short bursts up to 20 excess requestsnodelay— process burst immediately instead of queuing with delay
Exceeded limit returns 503 by default (or 429 with limit_req_status 429;).
Login endpoint stricter limit
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=1r/s;
location /api/login {
limit_req zone=login_limit burst=5 nodelay;
proxy_pass http://127.0.0.1:8080;
}limit_conn: Concurrent Connections
http {
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
limit_conn conn_limit 20;
location / {
proxy_pass http://127.0.0.1:8080;
}
}
}Code explanation:
- Max 20 simultaneous connections per IP for this
server - Helps slowloris-style abuse; tune for legitimate heavy users
Custom Status Code
limit_req_status 429;
limit_conn_status 429;Clients and monitors recognize Too Many Requests.
Whitelist Internal IPs
geo $limit {
default 1;
127.0.0.1 0;
10.0.0.0/8 0;
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=api_limit:10m rate=10r/s;When $limit_key is empty string, zone key is empty—advanced pattern to skip limits for trusted nets.
Combine with Security Headers
Rate limiting at edge; still validate auth in Spring Boot / Express. Do not expose admin tools without IP allow and app auth.
Testing Limits
for i in $(seq 1 50); do curl -s -o /dev/null -w '%{http_code}\n' http://api.example.com/api/ping; doneExpect mix of 200 then 429 or 503 when exceeding rate.
Watch error log:
sudo tail -f /var/log/nginx/error.logMay log limiting notices depending on level.
Production Considerations
| Topic | Note |
|---|---|
| Shared memory | Zone size (10m) holds many IP entries— increase if huge traffic |
| CDN in front | Rate limit by $http_x_forwarded_for or CDN header—careful spoofing |
| NAT users | Many users share one IP—limits may be too aggressive |
| API keys | Prefer app-level quotas per key; IP limit is coarse |
Warning
Do Not Rely on IP Alone
Mobile carriers and corporate NAT bundle many users—combine with auth and app throttles.
FAQ
limit_req in location vs server?
Zone defined in http; apply limit_req in server or location as needed.
Burst without nodelay?
Excess requests queued with delay—smoother but slower under spike.
Multiple zones?
Different zones for /api/ vs /login with different rates.
limit_req and HTTP/2?
Works per request; HTTP/2 multiplexing still counts requests.
Alternative tools?
Cloud WAF, API gateway, Redis rate limit in app—stack as needed.
503 vs 429?
Default 503 for limit_req—set limit_req_status 429 for clearer semantics.