SkillByAIOpen interactive version →

Lesson 19 / 25

Rate Limiting, Connection Limits and Request Size

Protect applications with limit_req, limit_conn and body size limits.

Keeping abusive traffic out

limit_req_zone defines a rate limit keyed by a variable, usually $binary_remote_addr (the client IP in compact form), with a shared memory zone and a rate such as 10r/s. limit_req zone=name burst=20 nodelay; applies it: requests beyond the rate are queued up to the burst size, and with nodelay burst requests are served immediately while still counting against the limit, which suits APIs. Excess requests are rejected, by default with 503; set limit_req_status 429; for the correct "Too Many Requests" status. Use different zones for different sensitivities: a strict limit on /login against brute force, a looser one on the API. limit_conn caps concurrent connections per key, useful for downloads. client_max_body_size (default 1 MB) limits request bodies; raise it only where uploads need it. Timeouts such as client_body_timeout and client_header_timeout reduce the impact of slow-request attacks.

Rate limiting with a burst allowance

Requests flow at the allowed rate; a burst bucket absorbs short spikes; the rest are rejected.

Figure 7.1 — limit_req with a burst queue.

Different limits for login and API

Strict on authentication, generous on normal API traffic.

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:20m   rate=20r/s;
limit_conn_zone $binary_remote_addr zone=perip:10m;

server {
    limit_req_status 429;
    limit_conn_status 429;
    client_max_body_size 2m;

    location = /login {
        limit_req zone=login burst=5;            # 5 per minute, small queue
        proxy_pass http://app_backend;
    }

    location /api/ {
        limit_req zone=api burst=40 nodelay;
        proxy_pass http://api_backend;
    }

    location /downloads/ {
        limit_conn perip 2;                      # at most 2 parallel downloads per IP
        limit_rate 2m;                           # 2 MB/s per connection
    }

    location /upload/ {
        client_max_body_size 50m;                # only here
        proxy_pass http://app_backend;
    }
}

Limit by the real client IP

Behind a CDN or load balancer, every request appears to come from a few proxy IPs, so a per-IP limit throttles everyone together. Configure real_ip first, or limit by an API key header instead.

Quick check: What does `nodelay` change in `limit_req zone=api burst=40 nodelay;`?

  • Burst requests are served immediately instead of being delayed to match the rate
  • It disables the limit
  • It returns 429 for every request
  • It only applies to POST requests
Answer

Burst requests are served immediately instead of being delayed to match the rate — Without nodelay, burst requests are queued and released at the configured rate.