Skip to main content

Rate Limiting and DDoS Protection

In this lesson, we'll explore how to protect your Nginx server from excessive traffic and malicious attacks using rate limiting and DDoS protection techniques.

Learning Goals

  • Configure rate limiting for different scenarios
  • Implement IP-based request limiting
  • Set up connection limiting
  • Create geographic-based restrictions
  • Monitor and test your protection rules

Understanding Rate Limiting

Rate limiting controls how many requests a client can make to your server within a specific time period. This prevents abuse and ensures fair resource distribution.

Basic Rate Limiting Configuration

Let's start with a simple rate limit that allows 10 requests per minute per IP address:

/etc/nginx/nginx.conf
http {
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/m;

server {
listen 80;
server_name example.com;

location /api/ {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://backend;
}
}
}
note

The $binary_remote_addr uses binary format for efficient memory usage. The 10m zone size can handle approximately 160,000 IP addresses.

IP-Based Request Limiting

Multiple Rate Limits

You can apply different rate limits to different parts of your application:

/etc/nginx/conf.d/rate-limiting.conf
limit_req_zone $binary_remote_addr zone=general:10m rate=100r/m;
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=api:10m rate=1000r/m;

server {
location / {
limit_req zone=general burst=50;
try_files $uri $uri/ =404;
}

location /login {
limit_req zone=login burst=10 nodelay;
proxy_pass http://auth_backend;
}

location /api/v1/ {
limit_req zone=api burst=200;
proxy_pass http://api_backend;
}
}

Connection Limiting

Connection limiting controls how many simultaneous connections a single IP can establish:

/etc/nginx/conf.d/connection-limiting.conf
limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
location /downloads/ {
limit_conn addr 5;
# Maximum 5 concurrent connections per IP for downloads
}

location /stream/ {
limit_conn addr 2;
# Maximum 2 concurrent streaming connections per IP
}
}

Geographic Restrictions

Block or limit traffic from specific countries or regions:

/etc/nginx/conf.d/geo-restrictions.conf
geo $blocked_country {
default 0;
# Block high-risk countries
CN 1;
RU 1;
KP 1;
}

map $blocked_country $block_access {
0 "";
1 403;
}

server {
location /admin/ {
if ($block_access) {
return 403;
}
# Admin panel content
}
}
warning

GeoIP databases require regular updates. Consider using the ngx_http_geoip_module for more accurate and maintainable geographic filtering.

DDoS Protection Strategies

Layered Protection Approach

/etc/nginx/conf.d/ddos-protection.conf
# Zone for tracking requests per IP
limit_req_zone $binary_remote_addr zone=flood:10m rate=30r/s;

# Zone for tracking connections per IP
limit_conn_zone $binary_remote_addr zone=conn:10m;

server {
# Global rate limiting
limit_req zone=flood burst=100 nodelay;

# Specific protections for vulnerable endpoints
location ~* \.(php|asp|aspx)$ {
limit_req zone=flood burst=20 nodelay;
limit_conn conn 5;
}

# Protect login endpoints more aggressively
location ~* /(login|admin|wp-admin) {
limit_req zone=flood burst=10 nodelay;
limit_conn conn 3;
}
}

Bot Protection

/etc/nginx/conf.d/bot-protection.conf
# Block common bad bots and scanners
map $http_user_agent $is_bad_bot {
default 0;
~*(bot|crawler|spider|scraper) 1;
~*(nmap|nikto|sqlmap) 1;
}

server {
if ($is_bad_bot) {
return 444; # Close connection without response
}

location / {
# Your normal configuration
}
}

Testing Your Configuration

Create a simple test to verify your rate limiting works:

test-rate-limit.sh
#!/bin/bash
URL="http://your-server.com/api/test"

echo "Testing rate limiting..."
for i in {1..15}; do
response=$(curl -s -w "%{http_code}" -o /dev/null $URL)
echo "Request $i: HTTP $response"
sleep 1
done

Monitoring and Logging

Monitor rate limiting events in your access logs:

/etc/nginx/conf.d/logging.conf
log_format rate_limit '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'limiter=$limit_req_status '
'conn_limiter=$limit_conn_status';

server {
access_log /var/log/nginx/rate_limit.log rate_limit;

location /api/ {
limit_req zone=api_limit;
limit_req_status 429; # Custom status code for rate limited requests
}
}

Common Pitfalls

  • Overly aggressive limits: Setting limits too low can block legitimate users
  • Memory allocation: Insufficient zone sizes can cause limits to stop working
  • IPv6 considerations: Ensure your configuration handles both IPv4 and IPv6 addresses
  • Testing gaps: Always test rate limiting with realistic traffic patterns
  • Static content: Don't apply aggressive limits to CSS, JS, and image files
  • API endpoints: Consider different limits for authenticated vs unauthenticated API calls

Summary

Rate limiting and DDoS protection are essential for maintaining service availability and security. By implementing layered protection strategies including request limiting, connection limiting, and geographic restrictions, you can effectively mitigate abuse while maintaining good user experience for legitimate traffic.

Nginx Rate Limiting and Bot Protection

What is the purpose of the `burst` parameter in Nginx rate limiting?

Question 1/4