📚 Learning Objectives
By the end of this module, you will: - Understand rate limiting concepts - Configure request rate limiting - Set up connection limiting - Implement IP-based limiting - Configure burst and delay - Handle rate limit whitelisting - Monitor rate limiting effectiveness
🚦 Rate Limiting Overview
Rate limiting protects your server by: - Preventing DDoS attacks - Reducing server load - Preventing abuse - Ensuring fair resource usage - Protecting against brute force attacks
📊 Request Rate Limiting
Basic Rate Limiting
http {
# Define rate limit zone
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
location / {
# Apply rate limit
limit_req zone=general;
proxy_pass http://backend;
}
}
}
Explanation:
- $binary_remote_addr: Key (client IP)
- zone=general:10m: Zone name and memory size (10MB)
- rate=10r/s: 10 requests per second
Rate Limit with Burst
http {
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
location / {
# Allow burst of 20 requests
limit_req zone=general burst=20;
proxy_pass http://backend;
}
}
}
How burst works: - Normal rate: 10 requests/second - Burst: Allows 20 extra requests in queue - Excess requests are delayed
Burst with No Delay
location / {
# Burst without delay (up to burst limit)
limit_req zone=general burst=20 nodelay;
proxy_pass http://backend;
}
Difference:
- burst=20: Queues requests, applies delay
- burst=20 nodelay: Allows burst, rejects after limit
🔢 Multiple Rate Limits
Different Limits for Different Paths
http {
# General limit
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
# Stricter limit for API
limit_req_zone $binary_remote_addr zone=api:10m rate=5r/s;
# Very strict for auth
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/s;
server {
location / {
limit_req zone=general burst=20;
# ...
}
location /api/ {
limit_req zone=api burst=10;
# ...
}
location /login {
limit_req zone=auth burst=3 nodelay;
# ...
}
}
}
Nested Rate Limits
http {
limit_req_zone $binary_remote_addr zone=global:10m rate=100r/s;
limit_req_zone $binary_remote_addr zone=per_location:10m rate=10r/s;
server {
# Global limit
limit_req zone=global burst=50;
location / {
# Additional per-location limit
limit_req zone=per_location burst=20;
# ...
}
}
}
🔌 Connection Limiting
Limit Connections per IP
http {
# Connection limit zone
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
server {
# Limit to 10 connections per IP
limit_conn conn_limit 10;
location / {
# ...
}
}
}
Limit Connections per Server
http {
limit_conn_zone $server_name zone=perserver:10m;
server {
server_name example.com;
# Limit to 100 connections per server
limit_conn perserver 100;
location / {
# ...
}
}
}
Multiple Connection Limits
http {
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server {
# Both limits apply
limit_conn perip 10;
limit_conn perserver 100;
location / {
# ...
}
}
}
🌐 Advanced Rate Limiting
Whitelist Specific IPs
http {
# Geo block for whitelisting
geo $limit {
default 1;
127.0.0.1 0; # Localhost
192.168.1.0/24 0; # Internal network
10.0.0.0/8 0; # VPN network
}
map $limit $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;
server {
limit_req zone=general burst=20;
# Whitelisted IPs bypass rate limit
}
}
Rate Limiting by Location
http {
geo $country_code {
default US;
# Add country mappings
}
map $country_code $rate_limit {
default "10r/s";
"CN" "5r/s";
"RU" "5r/s";
}
limit_req_zone $binary_remote_addr zone=dynamic:10m rate=10r/s;
server {
# Use dynamic rate based on location
limit_req zone=dynamic burst=20;
}
}
Rate Limiting by User Agent
http {
map $http_user_agent $limit_bots {
default "";
~*bot "1";
~*crawler "1";
~*spider "1";
}
map $limit_bots $limit_key {
default $binary_remote_addr;
"1" "";
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;
server {
# Bots bypass rate limit (or create separate limit)
limit_req zone=general burst=20;
}
}
📝 Custom Error Responses
Custom Rate Limit Error Page
http {
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
limit_req zone=general burst=20;
# Custom error page
error_page 429 /rate_limit.html;
location = /rate_limit.html {
root /usr/share/nginx/html;
internal;
}
location / {
# ...
}
}
}
Custom Error Response
location / {
limit_req zone=general burst=20;
# Return JSON for API
error_page 429 = @ratelimit;
location @ratelimit {
default_type application/json;
return 429 '{"error":"Too many requests","retry_after":60}';
}
}
📊 Rate Limit Status Headers
Add Rate Limit Headers
http {
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
location / {
limit_req zone=general burst=20;
# Add rate limit status headers
add_header X-RateLimit-Limit "10" always;
add_header X-RateLimit-Remaining "$limit_req_status" always;
# ...
}
}
}
🔍 Monitoring Rate Limits
Log Rate Limit Events
http {
log_format rate_limit '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rate_limit: $limit_req_status';
access_log /var/log/nginx/rate_limit.log rate_limit;
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
server {
limit_req zone=general burst=20;
# ...
}
}
Analyze Rate Limit Logs
# Count rate limit hits
sudo grep "PASSED\|REJECTED\|DELAYED" /var/log/nginx/rate_limit.log | wc -l
# Find IPs hitting limits
sudo awk '/REJECTED/ {print $1}' /var/log/nginx/rate_limit.log | sort | uniq -c | sort -rn
📋 Complete Rate Limiting Configuration
http {
# Rate limit zones
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=20r/s;
limit_req_zone $binary_remote_addr zone=auth:10m rate=1r/m;
# Connection limit zones
limit_conn_zone $binary_remote_addr zone=conn_limit:10m;
limit_conn_zone $server_name zone=perserver:10m;
# Whitelist
geo $whitelist {
default 1;
127.0.0.1 0;
192.168.1.0/24 0;
}
map $whitelist $limit_key {
0 "";
1 $binary_remote_addr;
}
limit_req_zone $limit_key zone=general:10m rate=10r/s;
server {
listen 80;
server_name example.com;
# Connection limits
limit_conn conn_limit 10;
limit_conn perserver 100;
# General rate limit
limit_req zone=general burst=20 nodelay;
# Custom error page
error_page 429 /rate_limit.html;
location = /rate_limit.html {
root /usr/share/nginx/html;
internal;
}
# Main location
location / {
proxy_pass http://backend;
}
# API with higher limit
location /api/ {
limit_req zone=api burst=50 nodelay;
proxy_pass http://backend;
}
# Auth with strict limit
location ~ ^/(login|register) {
limit_req zone=auth burst=3 nodelay;
proxy_pass http://backend;
}
}
}
🧪 Testing Rate Limits
Test with curl
# Single request
curl http://example.com
# Multiple rapid requests
for i in {1..30}; do curl http://example.com; done
# Test with delay
for i in {1..30}; do curl http://example.com; sleep 0.1; done
Test with Apache Bench
# 1000 requests, 100 concurrent
ab -n 1000 -c 100 http://example.com/
Monitor in Real-Time
# Watch error log
sudo tail -f /var/log/nginx/error.log | grep "limiting requests"
# Watch access log
sudo tail -f /var/log/nginx/access.log
📝 Exercises
- Set up basic rate limiting (10 requests/second)
- Configure burst handling
- Implement different limits for different paths
- Set up connection limiting
- Create IP whitelist for rate limits
- Configure custom error pages for rate limits
- Monitor rate limit effectiveness
- Test rate limits under load
✅ Checklist
- [ ] Understand rate limiting concepts
- [ ] Can configure request rate limiting
- [ ] Understand burst and nodelay options
- [ ] Can set up connection limiting
- [ ] Can whitelist IPs
- [ ] Can configure custom error responses
- [ ] Can monitor rate limiting
- [ ] Can test rate limits
➡️ Next Steps
Proceed to Module 5: Advanced Caching to learn advanced caching strategies.