Welcome! Log In Create A New Profile

Advanced

Re: If statement with $limit_req_status under location block with proxy_pass not working

Maxim Dounin
June 03, 2022 05:06PM
Hello!

On Thu, Jun 02, 2022 at 05:44:26PM -0400, acidiclight wrote:

> I'm trying to customize my response to rate-limited requests by keeping
> limit_req_dry_run on, and using an if statement depending on the value of
> $limit_req_status:
>
> This works as expected:
>
> limit_req_zone $binary_remote_addr zone=one:1m rate=2r/m;
>
> server {
>
> listen 80;
> server_name localhost;
>
> location / {
> # set rate limiting for this location
> limit_req zone=one burst=10 nodelay;
> limit_req_dry_run on;
>
> add_header X-my-var "$myvar" always;
>
> if ($limit_req_status = "REJECTED_DRY_RUN") {
> add_header X-custom-header "rejected" always;
> return 400 'rejected';
> }
>
> root /usr/share/nginx/html;
> index index.html;
> }
>
> }
>
> But once I replace root and index with a proxy_pass, the whole thing stops
> working:
>
> limit_req_zone $binary_remote_addr zone=one:1m rate=2r/m;
>
> server {
> resolver 8.8.8.8;
> listen 80;
> server_name localhost;
>
> location / {
> set $myupstream "myurl.com";
>
> # set rate limiting for this location
> limit_req zone=one burst=10 nodelay;
> limit_req_dry_run on;
>
> add_header X-limit-req-status "$limit_req_status" always;
>
> if ($limit_req_status = "REJECTED_DRY_RUN") {
> add_header X-custom-header "rejected" always;
> return 400 'rejected';
> }
>
> proxy_pass http://$myupstream;
> }
>
> }
>
> I added $limit_req_status to my log_format and can confirm that the value of
> $limit_req_status does get set to "REJECTED_DRY_RUN". I also see the header
> "X-limit-req-status" from the request set to "REJECTED_DRY_RUN".
>
> I'm assuming the issue is the way Nginx evaluates if statements that have
> unset variables at the beginning of the request? If so, any pointers on how
> to get this working? Thank you!

The rewrite module directives, notably "if", "set", and "return"
in your configuration, are evaluated while looking for a
configuration to process a request[1]. In contrast, limit_req limits
are evaluated before processing a request in a given
configuration. As such, both the above configurations are not
expected to work.

First one likely appear to work for you because you are testing it
with requests such as "/", involving an internal redirect to the
index file[2], so "if" acts on the limit_req results before the
internal redirect. Testing with direct link to a file will reveal
the it doesn't work too.

Proper solution to get things working would be to actually switch
off limit_req_dry_run. If you need to redefine response code
and/or add custom headers, consider using limit_req_status and/or
error_page instead. For example:

location / {
limit_req zone=one burst=10 nodelay;
error_page 503 = /rejected;
proxy_pass http://...;
}

location = /rejected {
add_header X-custom-header "rejected" always;
return 400 rejected;
}

Hope this helps.

[1] http://nginx.org/en/docs/http/ngx_http_rewrite_module.html
[2] http://nginx.org/en/docs/http/request_processing.html#simple_php_site_configuration

--
Maxim Dounin
http://mdounin.ru/
_______________________________________________
nginx mailing list -- nginx@nginx.org
To unsubscribe send an email to nginx-leave@nginx.org
Subject Author Posted

If statement with $limit_req_status under location block with proxy_pass not working

acidiclight June 02, 2022 05:44PM

Re: If statement with $limit_req_status under location block with proxy_pass not working

Maxim Dounin June 03, 2022 05:06PM

Re: If statement with $limit_req_status under location block with proxy_pass not working

acidiclight August 09, 2022 06:45PM



Sorry, only registered users may post in this forum.

Click here to login

Online Users

Guests: 193
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready