NGINX Rate Limiting — Configuring limit_req and limit_conn Modules
In this tutorial, you will learn about NGINX Rate Limiting. We cover key concepts, practical examples, and best practices to help you master this topic.
NGINX provides two modules for rate limiting: limit_req limits request rates using the leaky bucket algorithm, and limit_conn limits the number of concurrent connections from a single client.
What You'll Learn
- How to configure limit_req for request rate limiting
- How to configure limit_conn for connection limiting
- How to define zones, set burst sizes, and configure delays
Why It Matters
NGINX is often the first layer of defense in front of application servers. Configuring rate limiting at the NGINX level protects upstream servers before requests reach your application code, providing a lightweight and high-performance first line of defense.
Real-World Use
DodaTech's API Gateway uses NGINX with rate limiting configured at the reverse proxy layer. A partner sending 1000 req/s to an endpoint limited to 100 req/s gets a 503 Service Unavailable response from NGINX before the request reaches the application server, protecting backend resources.
flowchart LR
A["Client Request"] --> B["NGINX\nlimit_req_zone"]
B --> C{"Within\nlimit?"}
C -->|"Yes"| D["Application\nServer"]
C -->|"No (burst consumed)"| E["503 Service\nUnavailable"]
D --> F["Response"]
style B fill:#dbeafe,stroke:#2563eb
style E fill:#fecaca,stroke:#dc2626
Basic limit_req Configuration
# Define a shared memory zone for rate limiting
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
# Apply to a location block
server {
listen 80;
server_name api.dodatech.com;
location /api/ {
limit_req zone=api_limit;
proxy_pass http://backend:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Burst and Delay Configuration
# Allow bursts with a delay
limit_req_zone $binary_remote_addr zone=api_burst:10m rate=10r/s;
server {
location /api/ {
# burst=20 allows up to 20 extra requests in the queue
# nodelay processes burst requests immediately, not at the limited rate
limit_req zone=api_burst burst=20 nodelay;
# Without nodelay, burst requests are delayed:
# limit_req zone=api_burst burst=20;
proxy_pass http://backend:5000;
}
}
Multiple Zones and Conditions
# Define multiple rate limit zones for different purposes
limit_req_zone $binary_remote_addr zone=auth_limit:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=search_limit:10m rate=30r/m;
limit_req_zone $http_x_api_key zone=api_key_limit:10m rate=100r/m;
server {
# Authentication endpoints: strict limit
location /api/auth/ {
limit_req zone=auth_limit burst=3 nodelay;
proxy_pass http://backend:5000;
}
# Search endpoints: moderate limit
location /api/search/ {
limit_req zone=search_limit burst=10 nodelay;
proxy_pass http://backend:5000;
}
# Apply API key-based limit globally
location /api/v2/ {
limit_req zone=api_key_limit burst=50;
proxy_pass http://backend:5000;
}
}
Connection Limiting
# Limit concurrent connections per IP
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
# Limit connections per server
limit_conn_zone $server_name zone=server_limit:10m;
server {
location /api/ {
# Max 10 concurrent connections per IP
limit_conn conn_limit 10;
# Max 100 concurrent connections total
limit_conn server_limit 100;
limit_conn_status 503;
proxy_pass http://backend:5000;
}
}
Common Mistakes
1. Using $remote_addr Instead of $binary_remote_addr
$remote_addr as a string takes more memory in the zone. Use $binary_remote_addr for IPv4 (4 bytes) or IPv6 (16 bytes) to save space.
2. Not Setting Zone Size Appropriately
A 10m zone holds about 160,000 sessions. Estimate your concurrent unique IPs and size accordingly.
3. Forgetting to Apply limit_req_status
The default status code is 503. Use limit_req_status 429 to return the standard rate limit status code.
4. Applying Limits to Internal Redirects
NGINX internal redirects (like try_files) may bypass rate limits if the limit is applied at the wrong level.
5. Not Logging Rate Limit Events
Enable rate limit logging to debug issues: add limit_req_log_level warn to see blocked requests in logs.
Practice Questions
- What algorithm does NGINX limit_req use?
- What is the difference between burst and nodelay?
- How do you limit by API key instead of IP?
- What status code should NGINX return for rate limited requests?
- How many sessions can a 10m zone hold?
Answers
- Leaky bucket algorithm. 2. Burst allows a queue of excess requests; nodelay processes them immediately instead of at the limited rate. 3. Use
$http_x_api_keyas the zone key variable. 4. 429 (uselimit_req_status 429). 5. Approximately 160,000 sessions.
Challenge
Build an NGINX configuration that sets up different rate limit zones for authenticated and unauthenticated endpoints, uses API key extraction from headers, configures appropriate burst sizes, logs all rate limit events, and returns proper 429 status codes with Retry-After headers.
FAQ
Mini Project
Create a complete NGINX rate limiting setup with: separate zones for auth (5r/m), API (30r/m), and public endpoints (100r/m), burst configurations with and without nodelay, connection limiting, proper 429 status codes, Retry-After headers, and access log formatting that includes rate limit events.
What's Next
- Learn about Cloudflare rate limiting for edge-level protection
- Explore AWS API Gateway rate limiting
- Continue to distributed rate limiting with Redis cluster
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro