Marcio Cunha

How to block brute force attacks in Nginx with IP rate limiting

Learn how to protect your APIs against abusive traffic and brute force attacks by configuring limit_req and limit_req_zone directives in Nginx.

Marcio Cunha•4 min
Also available in:PortuguêsEspañol
Summary
  • Rate limiting controls the number of requests a single IP address can make within a specific timeframe.
  • The limit_req_zone directive creates shared memory zones to track incoming client activities.
  • The burst parameter allows the server to absorb legitimate traffic spikes without immediate errors.
  • The nodelay option processes bursts instantly up to the threshold to prevent artificial latency.
  • The HTTP 429 status code indicates that the client has exceeded the allowed request threshold.

Why protect your APIs with rate limiting in Nginx

Imagine your newly launched API starts receiving thousands of requests per second coming from the exact same IP address. At best, it is an unregulated web scraper; at worst, it is a malicious script attempting a brute force password attack or trying to take down your infrastructure through resource exhaustion. To shield web applications against this kind of abusive behavior, network engineers rely on request throttling, commonly known as rate limiting. If you have ever needed to solve similar challenges across other layers of your stack, you might also want to check out related insights on how to configure firewall rules with UFW on Linux to further harden your server perimeter.

In practice, Nginx acts as a strict doorman at the entrance of your digital ecosystem. It inspects every incoming packet, identifies where it originates based on the IP address, and decides whether the visitor can proceed or should receive a polite rejection. This mechanism prevents sudden traffic surges from overwhelming your database or exhausting available connection pools on the application server, ensuring stable service for legitimate users.

How the limit_req_zone directive works in practice

The heart of rate limiting in Nginx relies on two fundamental components: the memory zone and the enforcement directive. The first step involves defining who gets monitored and how much RAM is dedicated to this task. To achieve this, we use the http block in the main configuration file to declare the limit_req_zone directive, which carves out a reserved space in memory to store recent client IP activity histories.

When declaring a memory zone, we inform Nginx to allocate, for instance, ten megabytes to store client states. Each IP address consumes a tiny fraction of space in this tracking table, making it possible to monitor hundreds of thousands of concurrent visitors without degrading machine performance. This approach ensures that checks happen in fractions of a millisecond before the request even touches your core application.

Configuring the limit_req block and memory zone

To get our hands dirty, we need to edit the Nginx configuration file, typically located at /etc/nginx/nginx.conf or inside your site configuration files under the sites-available directory. The first step is to create the storage zone in memory and then apply the rule itself within the server context or a specific API route.

The code snippet below illustrates a typical, production-ready configuration ready to be deployed in your environment:

http {
# Defines a 10MB zone named 'api_limit' allowing 5 requests per second per IP
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=5r/s;

server {
listen 80;
server_name api.example.com;

location /api/v1/login {
# Applies the rule allowing a burst of 10 extra requests without delay
limit_req zone=api_limit burst=10 nodelay;

proxy_pass http://127.0.0.1:3000;
}
}
}

In this practical example, the binary_remote_addr variable captures the client IP address compactly to conserve memory. The rate is set to five requests per second (5r/s). If you need to understand how similar traffic spikes manifest in other backend technologies, you can read more about how to implement rate limiting in Node.js to strengthen your microservices resilience strategy.

Understanding the burst and nodelay parameters

Real users rarely send requests at mathematically perfect intervals; they click buttons quickly or load web pages containing multiple static assets in microseconds. This is precisely where the burst and nodelay parameters come into play. The burst setting creates a temporary tolerance margin to absorb legitimate access spikes above the primary rate threshold.

Without the nodelay directive, Nginx queues these excess requests and releases them spaced out over time, introducing artificial latency that can frustrate the user experience. When we append nodelay alongside the burst parameter, we instruct the server to let all requests within the tolerance margin pass instantly, applying throttling only if the total volume exceeds the combined limit.

How to test and validate rate limiting behavior

After applying configuration changes to Nginx and reloading the service with a syntax check command, it is crucial to validate whether the throttling mechanism works as intended. To achieve this, we can use command-line utilities like curl inside a quick loop to fire dozens of simultaneous requests against the protected endpoint.

If the configuration is correct, the initial requests will succeed, while the excess ones will immediately receive the HTTP 429 status code, indicating that the rate threshold has been reached. Below is the standard procedure to execute this basic stress test on your workstation:

  1. Open your operating system terminal and prepare the continuous firing command.
  2. Execute a simple loop using curl to send twenty rapid requests to the protected route.
  3. Inspect the response status codes returned by the server to confirm the appearance of the 429 error.
for i in {1..20}; do
curl -I http://api.example.com/api/v1/login
done

Should you need to investigate deeper packet delivery issues or atypical network layer behavior during load testing, advanced diagnostic tools such as those discussed in how to monitor HTTP/3 and QUIC traffic in Linux terminal can provide a surgical view of your traffic.

Conclusion and operational best practices

Implementing IP-based rate limiting rules in Nginx is one of the most effective and easily maintainable defenses against automated abuse in modern APIs. However, caution is required when tuning limits to avoid penalizing corporate networks where hundreds of employees share a single IP address behind a NAT proxy. Combining this strategy with authentication tokens and continuous monitoring guarantees a robust and secure environment.