Rate and connection limiting

NGINX · Advanced · 12 min

Rate limits protect login endpoints and APIs from abuse and keep one client from starving the others.

Request rate limiting uses the leaky bucket algorithm.

limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s; (in http) defines a shared zone keyed by client address. $binary_remote_addr is compact: a 10 MB zone tracks around 160,000 addresses. The key can be any variable, such as an API key header.

limit_req zone=api; in a location applies it. Without other parameters, requests arriving faster than the rate (here one per 100 ms) are rejected immediately, even short bursts. Two parameters fix that:

  • burst=20: queue up to 20 excess requests; they are released at the configured rate, so they are delayed.
  • nodelay: process queued burst requests immediately, while still counting them; requests beyond the burst are rejected. This is usually what APIs want: bursts are allowed, sustained abuse is not.
  • delay=8 (instead of nodelay): first 8 excess requests go without delay, the rest are delayed.

Rejected requests get 503 by default; set limit_req_status 429; for the correct "Too Many Requests". limit_req_dry_run on; logs what would be limited without enforcing it, ideal for tuning.

limit_conn_zone and limit_conn cap concurrent connections per key, for example to stop one client from opening hundreds of downloads.

Example

http {
    limit_req_zone  $binary_remote_addr zone=api:10m   rate=10r/s;
    limit_req_zone  $binary_remote_addr zone=login:10m rate=5r/m;
    limit_conn_zone $binary_remote_addr zone=perip:10m;
    limit_req_status 429;

    server {
        listen 80;
        location /api/ {
            limit_req zone=api burst=20 nodelay;   # bursts OK, abuse rejected
            proxy_pass http://127.0.0.1:8000;
        }
        location = /login {
            limit_req zone=login burst=3;          # excess queued, then 429
            proxy_pass http://127.0.0.1:8000;
        }
        location /downloads/ {
            limit_conn perip 2;                    # 2 concurrent downloads
        }
    }
}

Remember

  • limit_req_zone defines key, size and rate; limit_req applies it
  • burst queues excess; nodelay serves the burst at once
  • Use limit_req_status 429 and dry-run mode while tuning

Watch out for

  • Rate limiting by $remote_addr behind a load balancer: every client shares the balancer's IP; use the real_ip module first.

Check yourself

  1. rate=10r/s with burst=20 nodelay. A client sends 25 requests at once. What happens?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: nginx.org/en/docs/http/ngx_http_limit_req_module.html