Skip to content
EdgeServers
Blog

Layered rate limiting in Nginx — from limit_req_zone to Cloudflare and back

May 20, 2026 · 1 min read · by Sudhanshu K.

Rate limiting in Nginx is one of those things that exists in every config and works in maybe half of them. The default limit_req block buried in a sample config doesn't survive a real scrape, and certainly not a real attack. Worse, badly-tuned limits will block the legitimate Google crawler the day before your team realises why ranking dropped.

We layer rate limiting at three points: at the edge (Cloudflare or equivalent), at the perimeter (Nginx), and at the application (per-endpoint, per-user). This is the perimeter layer we ship on every managed Nginx install.

Per-route limits with a burst allowance

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s;
limit_conn_zone $binary_remote_addr zone=conn:10m;
 
server {
    location = /login {
        limit_req zone=login burst=3 nodelay;
        limit_conn conn 20;
        proxy_pass http://app;
    }
 
    location /api/ {
        limit_req zone=api burst=40 nodelay;
        proxy_pass http://app;
    }
}

/login is the brute-force target — 5 requests per minute is generous for humans and brutal for credential-stuffing bots. /api is much more permissive but still bounded.

The full write-up covers:

  • Edge → perimeter → origin: which attacks each layer catches
  • limit_req_status 429 and proper Retry-After headers so legitimate clients back off
  • geo directives to whitelist known good crawlers
  • The $binary_remote_addr vs $remote_addr memory consideration (4 vs 24 bytes per IP)
  • Coordinating Cloudflare rule changes with origin limit changes (don't trip both at once)
  • Reading the limit_req log lines to triage real attacks from misconfiguration

Reach out if your origin is currently being scraped and you're not sure how to read the logs.

Full article available

Read the full article