100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
DevOps

Rate Limiting in Nginx

How Nginx's limit_req and limit_conn modules throttle abusive or excessive traffic using a leaky bucket algorithm, burst allowances, and connection caps.

Performance & CachingIntermediate10 min readJul 10, 2026
Analogies

What Rate Limiting Protects Against

Rate limiting caps how many requests a single client can send in a given period, protecting backend applications from both malicious abuse — credential stuffing on a login form, aggressive scraping, or a bug causing a client to hammer an endpoint in a retry loop — and from accidental traffic spikes that would otherwise overwhelm capacity meant for the broader user base. Nginx implements this primarily through the limit_req module, which uses a leaky bucket algorithm to smooth bursts down to a configured steady rate rather than a strict, jagged per-second cutoff.

🏏

Cricket analogy: Rate limiting is like an over-rate rule capping how many deliveries a bowling side can send down in a set period — Nginx caps how many requests a client can fire at the server per second to prevent one aggressive client from overwhelming the innings.

The limit_req_zone and limit_req Directives

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; declares a shared memory zone that tracks recent request timestamps per client key, here the client's IP address, and enforces a steady rate of 10 requests per second. The limit_req directive then applies that zone inside a specific location block, meaning the same server can enforce different rate policies for different endpoints simply by referencing different zones with different rates.

🏏

Cricket analogy: limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; is like an over-rate regulation stating each bowler (client IP) may send down at most 10 deliveries per second, with a 10MB shared ledger (zone) tracking every bowler's recent activity.

nginx
http {
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    server {
        location /api/ {
            limit_req zone=api burst=20 nodelay;
            limit_conn addr 10;
            limit_req_status 429;
            proxy_pass http://backend;
        }
    }
}

Burst and Nodelay

The burst parameter, as in limit_req zone=api burst=20 nodelay;, allows a client to briefly exceed the configured steady rate by up to 20 requests before further requests are rejected, absorbing short, legitimate traffic spikes like a page loading several assets at once. Without nodelay, those burst requests are queued and released gradually to match the base rate, adding latency; with nodelay, requests within the burst allowance are processed immediately, trading strict pacing for lower latency during brief spikes.

🏏

Cricket analogy: burst=20 nodelay; is like allowing a bowler to send down a quick flurry of 20 deliveries in a rain-shortened over scramble without the umpire making them wait between balls, as long as they don't exceed that burst allowance.

Rate-limited requests return HTTP 503 by default; use limit_req_status 429; to return the more semantically correct 'Too Many Requests' status code that clients and monitoring tools expect.

Connection Limits and Whitelisting

limit_conn_zone and limit_conn cap a different threat entirely: how many simultaneous connections one client can hold open at once, regardless of request rate, which guards against slow-loris-style abuse or a client opening excessive parallel connections to a single expensive endpoint. Exempting trusted clients such as internal health checks or a known CDN's IP range from these limits is often done with the geo or map modules, but that exemption must be based on a verified source address, never a client-controllable header, or the whitelist itself becomes an attack surface.

🏏

Cricket analogy: limit_conn_zone capping simultaneous connections per client is like a stadium rule limiting how many gates one supporter's group ticket can be used at simultaneously, preventing one credential from being used to flood multiple entry points at once.

Trusting X-Forwarded-For to whitelist IPs for rate-limit exemption is dangerous behind a misconfigured proxy chain — that header is client-controlled unless your edge proxy strictly overwrites it, letting attackers spoof a whitelisted address.

  • limit_req_zone defines a shared memory zone and a maximum sustained rate keyed by a variable like $binary_remote_addr.
  • limit_req applies that zone to a specific location, and burst allows short traffic spikes above the base rate.
  • nodelay processes burst requests immediately instead of queuing and spacing them out, at the cost of allowing brief spikes through faster.
  • limit_conn and limit_conn_zone cap simultaneous open connections per client, complementing rate-based limiting.
  • limit_req_status 429; returns the semantically correct status code instead of the default 503.
  • Whitelisting IPs for rate-limit exemption must rely on a trusted, proxy-verified address, not a client-spoofable header.
  • Combine per-IP rate limiting with connection limits to defend against both flooding and slow-connection abuse.

Practice what you learned

Was this page helpful?

Topics covered

#DevOps#NginxStudyNotes#RateLimitingInNginx#Rate#Limiting#Nginx#Protects#StudyNotes#SkillVeris#ExamPrep