Nginx Rate Limiting – Using Multiple Rate Rules

networkingnginxrate-limiting

Using nginx rate limiting, using this rule as an example:

limit_req_zone $request_limiting_zone_key zone=request_limiting_search:20m rate=30r/m;

This will set 30 requests per minute. However what if I wanted to stack a second rule, so the logic is "30 requests per minute, or 1 request per second. Whichever comes first"

The reason for this is we still want a cap of 30/min but there are some weird attempts that we're seeing a spam of 10x requests in a 1-2 second period. This causes some issues when requests come through that fast. So we would like to limit users to 1 request a second, AND a cap of 30 per minute.

I read the doc reference but didn't see much around stacking different rate rules.

Is this possible? If so, what would be the syntax?

Best Answer

It is perfectly valid to apply multiple zones to the same block. You may also create multiple zones that store requests for the very same key (typically some prefix of client IP address). It only costs minimal processing and memory.

The following will limit users, identified by their network address, both in second and minute intervals - and allow them to temporarily exceed the defined limit for short bursts. You want to allow that, as it will make your website appear less broken for user with unreliable input devices and/or network access - they might issue the same request twice:

map $remote_addr $request_limiting_zone_key {
    # [..]
}
limit_req_zone $request_limiting_zone_key zone=request_limit_search_second:10m rate=1r/s;
limit_req_zone $request_limiting_zone_key zone=request_limit_search_minute:10m rate=30r/m;

 # [..]

location /search {
    limit_req zone=request_limit_search_second burst=3;
    limit_req zone=request_limit_search_minute burst=3;
}

That being said, if your web server cannot handle a short burst of search requests, maybe you are going to need to offload your search engine to some other machine or apply a different kind of rate limit. You need a significant margin between typical human usage and usage which exceeds your machines ability to keep up. Otherwise you might not find a safe value between annoying legitimate users and failing to restrict abusive/bot usage.