Layer 7 Distributed Denial of Service (DDoS) and brute-force login attacks can saturate server CPU resources, lock database connections, and degrade performance for legitimate users. While large-scale network floods require upstream volumetric mitigation, application-layer spikes and aggressive scrapers can often be stopped directly at the web server level.

Implement Rate Limiting in Nginx for DDoS Protection

Nginx includes built-in rate-limiting modules powered by the leaky-bucket algorithm. By enforcing explicit request quotas per client IP address, you can protect your VPS resources and maintain steady uptime.

What is Rate Limiting?

Rate limiting is the process of controlling how frequently a client (usually identified by IP address) can make requests to a server. This prevents a single client from overwhelming your system and helps ensure fair resource distribution among all users.

For example, you can allow 10 requests per second per IP and if a client exceeds that, Nginx will delay or reject further requests.

Step 1: Understand Nginx Rate Limiting Directives

Note: Before proceeding, make sure your server is installed with Nginx. Here we use an Ubuntu 22.04 server.

Nginx provides two main directives for rate limiting:

  • limit_req_zone: defines a shared memory zone to store request states and sets the rate limit.
  • limit_req: applies the defined rate limit to a specific location or route.

Step 2: Define a Rate Limiting Zone

Open your main Nginx configuration file, usually found at /etc/nginx/nginx.conf, and add the following inside the http block:

http {
    # Define a zone named 'one' with a 10MB shared memory limit
    # Allow 10 requests per second per IP
    limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
}

Explanation:

  • $binary_remote_addr: uses the client’s IP as the key for limiting. It is more efficient than $remote_addr as it stores IPs in binary format.
  • zone=one:10m: creates a 10MB zone named ‘one’. A 10MB zone can hold states for around 160,000 IP addresses.
  • rate=10r/s: sets the request rate to 10 requests per second.

Step 3: Apply Rate Limiting to a Server Block

Now, inside your website configuration file (e.g., /etc/nginx/sites-available/example.conf), add the following under your server block:

server {
    listen 80;
    server_name example.com;
    
    location / {
        limit_req zone=one burst=20 nodelay;
        proxy_pass http://localhost:8080;
    }
}

Note: If you do not have a domain name yet, you can use your server’s IP address instead of example.com throughout the configuration.

Explanation:

  • limit_req zone=one: applies the limit zone defined earlier.
  • burst=20: allows short bursts of up to 20 requests before throttling. This accommodates legitimate traffic spikes.
  • nodelay: rejects requests that exceed the burst limit immediately instead of queuing them. If you omit nodelay, Nginx will queue extra requests (up to the burst limit) and process them gradually.

Step 4: Test and Reload Nginx

After making changes, check your configuration for syntax errors:

nginx -t

Terminal Output Example:

root@racknerd-ed0eec2:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
root@racknerd-ed0eec2:~#

If no errors are reported, reload Nginx:

systemctl reload nginx

You can then test your rate limit using a tool like ab (Apache Benchmark) or curl:

ab -n 100 -c 20 http://example.com/

If you exceed the limit, Nginx will return: “HTTP/1.1 503 Service Temporarily Unavailable”.

Terminal Output Example:

root@racknerd-ed0eec2:/etc/nginx/sites-enabled# ab -n 100 -c 20 http://172.245.184.146/
This is ApacheBench, Version 2.3 <$Revision: 1879490 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking 172.245.184.146 (be patient)......done

Server Software:        nginx/1.18.0
Server Hostname:        172.245.184.146
Server Port:            80

Document Path:          /
Document Length:        166 bytes

Concurrency Level:      20
Time taken for tests:   0.034 seconds
Complete requests:      100
Failed requests:        79
   (Connect: 0, Receive: 0, Length: 79, Exceptions: 0)
Non-2xx responses:      100
Total transferred:      37440 bytes
HTML transferred:       19760 bytes
Requests per second:    2944.21 [#/sec] (mean)
Time per request:       6.793 [ms] (mean)
Time per request:       0.340 [ms] (mean, across all concurrent requests)
Transfer rate:          1076.48 [Kbytes/sec] received

Conclusion

Implementing rate limiting in Nginx is a straightforward yet powerful method to mitigate unwanted traffic and reduce the risk of small-scale DDoS attacks. By carefully tuning request and connection limits, you can maintain high availability and ensure legitimate users enjoy a smooth experience even under traffic spikes.

Your Nginx-powered server can be made much more resilient with a few configuration lines; this small change can have a significant impact on your security posture.


📺 Watch the Video Tutorial on RackNerdTV

For more web server configurations and tips, check out our guide on installing the VestaCP control panel which utilizes Nginx, available on the RackNerdTV YouTube channel:

At RackNerd, you can deploy a Linux VPS with the flexibility and root-level access needed to configure web servers like Nginx exactly as you need them. If you prefer a managed environment where server security and configuration are handled for you, check out our shared web hosting services.

👉 Visit https://racknerd.com to learn more about our hosting solutions.

Server Hosting Solutions by RackNerd:

Shared Hosting
cPanel Web Hosting in US, Europe, and Asia datacenters
Logo
Reseller Hosting
Create your new income stream today with a reseller account
Logo
VPS (Virtual Private Server)
Fast and Affordable VPS services - Instantly Deployed
Logo
Dedicated Servers
Bare-metal servers, ideal for the performance-demanding use case.
Logo

Leave a comment

Your email address will not be published. Required fields are marked *