Operate and troubleshoot
Control rate and connections
Limit abusive request rates and concurrent work while preserving normal bursts and clear failure behavior.
Nginx can limit request rate per key and concurrent connections per key. This protects expensive endpoints from one aggressive client — a runaway script, a scraper, a brute-force attempt — without touching application code.
Rate limiting takes two directives. In the http context you define a zone; in the location you apply it:
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
server {
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
proxy_pass http://127.0.0.1:3000;
}
}
The key is $binary_remote_addr, the client IP in compact form, so each address gets its own budget of 10 requests per second. The 10-megabyte zone holds the counters for roughly 160,000 addresses.
The burst is what keeps real users happy. A browser opening a page fires a burst of requests in the same instant — HTML, then a volley of assets and API calls. Without burst, everything past the steady rate in that instant is rejected, and ordinary page loads break. burst=20 allows 20 requests to exceed the rate momentarily, and nodelay serves them immediately instead of queueing them.
limit_req_status 429 makes rejections return 429 Too Many Requests. The default is 503, which monitoring systems read as “server broken” rather than “client throttled” — set 429 so your dashboards stay honest.
Concurrent connections are a separate limit for long-held work like downloads:
limit_conn_zone $binary_remote_addr zone=perip:10m;
location /downloads/ {
limit_conn perip 5;
}
Test both behaviors separately: normal traffic first, then an intentional excess:
for i in $(seq 1 40); do
curl -s -o /dev/null -w "%{http_code}\n" https://app.example.com/api/ping
done
# 200 x ~30, then 429 for the rest
The first ~30 requests pass (rate plus burst), then rejections start. Each rejection also writes a limiting requests line to the error log, which is how you’ll spot throttling in production.
Choose a key that represents the client boundary you trust. Behind a CDN or load balancer, $binary_remote_addr is the proxy’s address, so all your users share one bucket and throttle each other — restore the real client IP first, or key on something else. And keep perspective: edge limits complement application authorization and business rules; they do not replace them.
Lesson completed