Nginx Rate Limiting Mastery: Leaky Bucket, Burst Handling & Dynamic Throttling

This guide covers Nginx rate limiting via ngx_http_limit_req_module (leaky bucket algorithm), connection limiting with ngx_http_limit_conn_module, and bandwidth throttling using limit_rate, limit_rate_after, and proxy_limit_rate, including burst handling, nodelay, whitelists, and dynamic rate control via map variables.

Architect's Guide
Architect's Guide
Architect's Guide
Nginx Rate Limiting Mastery: Leaky Bucket, Burst Handling & Dynamic Throttling

Overview

Rate limiting protects systems by restricting input/output traffic. Public-facing sites face crawlers, attacks, and traffic spikes that can overwhelm servers. Nginx provides two core limiting approaches: request rate limiting and connection limiting, plus bandwidth throttling for uploads/downloads.

Request Rate Limiting (ngx_http_limit_req_module)

Uses the leaky bucket algorithm: requests queue in a FIFO buffer processed at a fixed rate. Excess requests are discarded (default 503). Two directives configure this: limit_req_zone key zone rate — defines shared memory zone and rate. limit_req zone=name [burst=number] [nodelay] — activates limiting for a location.

Basic Configuration

limit_req_zone $binary_remote_addr zone=test:10m rate=2r/s;
server {
  location / {
    limit_req zone=test;
  }
}

Key parameters:

key : $binary_remote_addr (binary client IP) — 4 bytes for IPv4, 16 for IPv6, vs 7–15 bytes for $remote_addr, saving memory.

zone : test:10m — 10 MB zone stores ~160,000 IP entries (1 MB ≈ 16,000). Stale entries (>60s unused) are evicted; if space exhausted, returns 503.

rate : 2r/s — tracked per millisecond, so 1 request per 500 ms. Excess requests within the interval are rejected.

Without burst, the bucket has zero capacity; only requests arriving exactly at the rate interval pass.

Handling Burst Traffic with burst

limit_req zone=test burst=5;
burst=5

allows 5 extra requests to queue. At rate=2r/s (500 ms/request), 10 simultaneous requests: 1 processed immediately, 5 queued, 4 rejected. Queued requests are dequeued every 500 ms. The 5th queued request waits 2 seconds (500 ms × 4).

Eliminating Queue Delay with nodelay

limit_req zone=test burst=5 nodelay;
nodelay

processes the first request and all queued requests immediately. Queue slots still release at the configured rate (500 ms each), so long-term throughput remains capped at rate. Rejected requests (beyond burst) still get 503.

Whitelist via geo + map

geo $limit {
  default 1;
  10.0.0.0/8 0;
  192.168.0.0/24 0;
}
map $limit $limit_key {
  0 "";
  1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=mylimit:10m rate=2r/s;
geo

sets $limit=0 for whitelisted subnets. map translates 0 to empty string (no limiting) and 1 to binary IP. Empty key disables limiting for those IPs.

Multiple limit_req Directives

limit_req_zone $limit_key zone=mylimit:10m rate=2r/s;
limit_req_zone $binary_remote_addr zone=myLimit2:10m rate=10r/s;
server {
  location ~* \.(html)$ {
    limit_req zone=mylimit burst=5 nodelay;
    limit_req zone=myLimit2 burst=5 nodelay;
  }
}

Both limits apply. Whitelisted users bypass mylimit but hit myLimit2 (10 r/s). Non-whitelisted users must satisfy both; the stricter (2 r/s) wins.

Connection Limiting (ngx_http_limit_conn_module)

Limits concurrent connections via limit_conn_zone and limit_conn.

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
  location ~* \.(html)$ {
    limit_conn perip 10;
    limit_conn perserver 100;
  }
}
limit_conn perip 10

: max 10 simultaneous connections per client IP. limit_conn perserver 100: max 100 concurrent connections per virtual host.

Note: A connection is counted only after the request header is processed by the backend server.

Bandwidth Throttling (ngx_http_core_module)

limit_rate

server {
  location / {
    limit_rate 4k;
  }
}

Limits bytes per second per connection (default unit: bytes/s, not bits).

Can use a variable for dynamic rates.

Applies per connection: two connections = 8 kB/s aggregate.

limit_rate_after

server {
  location / {
    limit_rate_after 500k;
    limit_rate 4k;
  }
}

First 500 kB transferred unrestricted; thereafter limited to 4 kB/s. Use cases: segmented download throttling, video streaming (fast initial frame load, then throttle to reduce pre-buffering costs).

proxy_limit_rate

Limits rate between Nginx and upstream servers. Requires proxy_buffering on. Syntax: proxy_limit_rate rate; (default 0 = unlimited). Context: http, server, location. Added in v1.7.7.

Dynamic Rate Limiting with Variables

Time-based (using SSI $date_local )

map $date_local $limit_rate_time {
  default 4K;
  ~(00:|01:|02:|03:|04:|05:|06:|07:).*:.* 16K;
  ~(08:|12:|13:|18:).*:.* 8K;
  ~(19:|20:|21:|22:|23:).*:.* 16K;
}
limit_rate $limit_rate_time;

Regex matches hour prefixes in $date_local to assign rates per time band.

Cookie-based (e.g., VIP tiers)

map $cookie_User $limit_rate_cookie {
  gold 64K;
  silver 32K;
  copper 16K;
  iron 8K;
}
limit_rate $limit_rate_cookie;

Maps cookie value to rate, enabling per-user-tier throttling.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

dynamic-configurationnginxweb-serverrate-limitingleaky-bucketconnection-limitingbandwidth-throttlingburst-handling
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.