Search code examples
nginxcachingreverse-proxy

nginx - request limits for uncached content not working, weird behavior


I want to impose a request limit for uncached content on my NGINX reverse proxy. I have multiple locations defined and content can get cached or won't get cached due to other rules. So I can not set a request limit just for a location, I have to handle this differently.

According to the documentation in https://www.nginx.com/blog/rate-limiting-nginx/#Advanced-Configuration-Examples, I can use the map feature in order to impose a request limit. So I tried this and created following configuration snippet:

map $upstream_cache_status $limit {
  default 1;
  MISS 1;
  HIT 0;
}

map $limit $limit_key {
  0 "";
  1 $binary_remote_addr;
}

limit_req_zone $limit_key zone=req_zone:10m rate=5r/s;

So in order to test my map first, I have added following to my location:

add_header X-Test $limit;

And I see that it works! Every resource that is cached ($upstream_cache_status = HIT), $limit seems to be 0. Every uncached content ($upstream_cache_status = MISS), $limit is 1.

Now comes the weird behaviour. As soon as I add limit_req zone=req_zone burst=10 nodelay; into my location, $limit seems to be stuck at 1, no matter if the $upstream_cache_status is HIT or MISS.

The location looks like this:

location ~* \.(jpg|jpeg|png|gif|webp|svg|svgz|ico|pdf|doc|docx|xls|xlsx|csv|zip|gz|woff|woff2|ttf|otf|eot)$ {

            limit_req zone=req_zone burst=10 nodelay;

            [...]
            add_header X-Test $limit;
            [...]

        }

Is this a NGINX bug or am I missing something here? NGINX version is 1.20.1 on AlmaLinux 8.5.


Solution

  • Rate limiting works first, on request phase. Caching works later, on content phase (guess).

    So, when limiter works, there is no information about cache status yet.