Virtually every website experiences a sudden surge in traffic at some point. Sometimes the reason is quite pleasant - one of the posts has unexpectedly gone viral, and thousands of visitors have flooded the site at once. Unfortunately, this doesn’t happen as often as we’d like. Much more often, the surge is caused by automated scanners, persistent bots, or simple DDoS attacks. While they usually lack the power to affect large-scale infrastructure, they are quite capable of pushing a small VPS or a standalone web server to its limits.
There’s a fairly simple way to reduce this load. The Nginx web server includes a rate limiting mechanism that restricts the frequency of requests from a single client. Of course, it won’t replace full-fledged DDoS protection, but it can filter out a significant portion of unwanted traffic right at the web server level. These requests will never reach the application, which means that the CPU, memory, and other resources will be used much more efficiently.
What Is Rate Limiting
Rate limiting is the restriction on the number of requests a single client can send within a specific time period. Nginx typically tracks clients by IP address, though other parameters can be used if necessary.
Here’s a simple analogy. Imagine a small café with a single cash register. If customers approach one at a time, everything runs smoothly. But as soon as a large group takes up the line all at once, the rest of the customers have to wait. A server under heavy load behaves in much the same way. Rate limiting restricts the rate of requests from each source, so a single client can no longer monopolize all available resources.
This mechanism helps in a wide variety of situations. For example, it mitigates the effects of:
- simple HTTP flood attacks;
- password brute-force attempts;
- automated bot scans of the site;
- overly aggressive parsers.
And if the limits are set reasonably, regular visitors won’t even notice them. However, suspicious activity will hit the set limit before it can place a serious load on your server.
How Request Limiting Works in Nginx
The request limiting mechanism in Nginx is built around two directives: limit_req_zone and limit_req. The first one defines a memory zone where the server stores information about how often each client accesses the site.
For example:
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
Several parameters are used here:
$binary_remote_addr -this is the client’s identifier, which is usually its IP address in binary format;zone=api_limit:10m -this is the zone name and the amount of memory allocated for storing statistics;rate=10r/s -a limit of ten requests per second for each client.
But this rule alone is not enough, since it only creates a zone with settings. For the limit to take effect, it must be applied to the appropriate location, server, or even the entire httpblock.
For example:
location / {
limit_req zone=api_limit burst=20 nodelay;
}
Here, two additional parameters come into play.
burst=20 -allows the main limit to be briefly exceeded. This is useful for normal website operation, since a browser rarely loads a page with a single request; instead, it typically requests the HTML document, style sheets, JavaScript, images, and other resources simultaneously—sometimes numbering several dozen.
nodelay -changes the behavior when the limit is exceeded. If specified, excess requests are rejected immediately; without it, Nginx will attempt to briefly queue them and process them later, if the specified rate allows.
What Values to Choose
Most often, problems arise not because the settings are too lenient, but because they are too strict. The desire to limit the flow of requests as much as possible is quite understandable, but more often than not, this approach ends up hindering regular visitors.
For example, a limit of 2r/s seems safe, but in reality it often turns out to be too strict, since even without any attack, a user can quickly refresh a page, open several tabs, or perform several actions in a row in the web interface. As a result, some requests will receive the response 429 Too Many Requests, even though no malicious activity occurred.
For most projects, you can use the following guidelines:
- corporate website - 5–10 requests per second;
- online store - 10–20 requests per second;
- REST API - typically 20–50 requests per second, provided the operations aren’t too resource-intensive;
- admin panel - 2–5 requests per second with a low
burstvalue.
IMPORTANT! These figures should not be considered universal, but they help you choose an initial configuration. After that, you should examine actual Nginx logs, the nature of the load, and user behavior, and then decide whether to adjust the limits up or down. Sometimes, after a few days of monitoring, it becomes clear that the limit can be raised, and sometimes the opposite is true.
Protecting the Login Page
It’s worth mentioning the login form separately, as it’s best to limit it individually. This is where brute-force password attacks most often occur, when an automated script takes a list of usernames, substitutes passwords, and rapidly sends hundreds of requests in a row.
An example configuration for such a page might look something like this:
location = /login {
limit_req zone=login_limit burst=5 nodelay;
}
With this rule in place, a single IP address will no longer be able to send a huge number of login attempts without pauses. Some requests will be rejected immediately, and the application won’t have to check the username and password against the database every single time.
In this case, the load drops significantly. At the same time, brute-force attacks become less effective for the attacker, since the attack speed slows to an unacceptable level, and suspicious requests are easier to spot in the web server logs.
What Rate Limiting Can’t Do
But like any other mechanism, rate limiting has its limitations. It handles simple scenarios quite well, but against certain types of attacks, its capabilities may no longer be sufficient.
For example, if requests are coming simultaneously from tens of thousands of IP addresses, and each source stays within the set limit, Nginx won’t detect anything unusual. To counter distributed DDoS attacks on this scale, CDNs, traffic filtering systems, or specialized anti-DDoS services are typically used.
Incidentally, there’s another important point to consider. Rate limiting monitors only the frequency of requests and does not analyze the content of HTTP requests at all; therefore, this mechanism cannot detect complex application-level attacks, such as attempts to exploit vulnerabilities or malicious sequences of requests.
Therefore, rate limiting is best viewed as one line of defense - it won’t solve all problems on its own, but when combined with other security measures, it significantly reduces risks and helps the server withstand many simple attacks without serious consequences.
Useful Recommendations
The effectiveness of rate limiting largely depends on how carefully the settings are configured. As we mentioned above, there are no one-size-fits-all values here, but there are several practical rules that help avoid common mistakes.
First, you shouldn’t apply limits to absolutely all requests. Static files, such as images, style sheets, JavaScript, and so on, rarely cause a significant load on their own. It’s much more useful to limit access to login pages, APIs, search forms, and other endpoints that bots most frequently target.
After changing the configuration, it’s a good idea to monitor the Nginx logs for a few days. If the response code 429 Too Many Requests starts appearing regularly for regular users (this sometimes happens after overly aggressive settings), then it’s best to review the limits.
And here’s another important point. Rate limiting works well in conjunction with other security measures. Tools such as a firewall, Fail2Ban, a WAF, and properly configured connection timeouts - all of these complement each other. As a result, the server becomes much more resilient to automated attacks and spikes in unwanted traffic.
Conclusion
You can configure rate limiting in Nginx in just a few minutes. The effect is immediately noticeable, as the server begins to better handle simple DDoS attacks, mass scanning, and persistent bots. And this mechanism requires almost no additional resources.
For VPS, this configuration has long been considered best practice. It reduces the likelihood that a single source will be able to overload your server, thereby helping to preserve performance headroom during sudden spikes in request volume.
Of course, rate limiting is no substitute for comprehensive protection against distributed DDoS attacks. But together with a firewall, Fail2Ban, WAF, and other security measures, it creates an additional line of defense that blocks a significant portion of unwanted traffic before requests even reach the application. And if the limits are set correctly, regular visitors will most likely not even notice this mechanism at work.