Limit_req and limit_conn in rewrite modules if statement

Hello, I would like to see if it’s possible to get limit_conn and
limit_req
working with the rewrite modules if statement. I have seen some
discussion
about this in the mailing list already saying to use stuff like throwing
a
410 code and having that 410 code handled by a @named location that
handles
requests that should not be limited, such as …

location / {
error_page 410 = @nolimit;

if ($http_user_agent ~ Googlebot) {
return 410;
}

limit_req zone=one burst=4;


}

location @nolimit {

}

I also know about how if statements are considered evil and should be
avoided where possible, but I am working with dynamically generating
config
files which support multiple upstreams, with different upstream options
per
location directive with various features involved. I would like to be
able
to set a variable that I can than use in an if statement to determine if
limit_con or limit_req should be used. For example…

set $Whitelisted “No”;
if ($http_user_agent ~ (googlebot|bingbot)) {
set $Whitelisted “Yes”;
}
if ($Whitelisted ~* “No”) {
limit_conn conlimit-one 5;
limit_req zone=limit-half burst=9;
}

Is there any possibility of this functionality being unlocked in the
nginx
code? I really need this functionality, and I hope it’s not a big deal
to
do.
Is there are particular reason why this module does not work with the
rewrite if statement?

Posted at Nginx Forum:

To elaborate a bit more, in a single location I may end up with
something
like this…

set $Whitelisted “No”;
if ($GeoList1 = allow) {
set $Whitelisted “Yes”;
}
if ($GeoList5 = allow) {
set $Whitelisted “Yes”;
}
if ($http_user_agent ~ (googlebot|bingbot)) {
set $Whitelisted “Yes”;
}
if ($Whitelisted ~* “No”) {
limit_conn conlimit-one 5;
limit_req zone=limit-half burst=9;
}

So that I can allow both IPs and user agents to avoid getting limited.

Posted at Nginx Forum:

On 18 November 2013 20:57, Nam [email protected] wrote:

if ($http_user_agent ~ (googlebot|bingbot)) {
set $Whitelisted “Yes”;
}
if ($Whitelisted ~* “No”) {
limit_conn conlimit-one 5;
limit_req zone=limit-half burst=9;
}

Have you looked at using map{}s as the limit_* settings’ arguments
instead? They’re much nicer than sequential if()s, which may not even
achieve what you want to.

J

Can you give an example of how I would accomplish the desired if
statement I
posted? I do not see how i could get map to do that myself.

Posted at Nginx Forum:

On Mon, Nov 18, 2013 at 02:49:27PM -0500, Nam wrote:

Hi there,

I would like to see if it’s possible to get limit_conn and limit_req
working with the rewrite modules if statement.

Not according to the current documentation.

I suspect that patches will be welcome, if they fit the usual criteria.

I have seen some discussion
about this in the mailing list already saying to use stuff like throwing a
410 code and having that 410 code handled by a @named location that handles
requests that should not be limited

You don’t seem to say why that setup doesn’t work for your situation.

I also know about how if statements are considered evil

Yes.

and should be avoided where possible

No.

“if” inside “location” can be a problem. Otherwise, it should be fine.

but I am working with dynamically generating config
files which support multiple upstreams, with different upstream options per
location directive with various features involved.

You may want to rethink the design, based on the nginx features
available.

I would like to be able
to set a variable that I can than use in an if statement to determine if
limit_con or limit_req should be used.

As above, if you’re doing that, you’re not using current nginx.

For example…

set $Whitelisted “No”;
if ($http_user_agent ~ (googlebot|bingbot)) {
set $Whitelisted “Yes”;
}
if ($Whitelisted ~* “No”) {
limit_conn conlimit-one 5;
limit_req zone=limit-half burst=9;

Somewhere, you have defined limit_conn_zone to match that. Can you
redefine that to use a new variable that takes the value you want, if
$Whitelisted is “No”, and is empty if $Whitelisted is “Yes” – in this
case, if $http_user_agent matches those patterns?

That should be doable without patching nginx.

f

Francis D. [email protected]

Hello!

On Tue, Nov 19, 2013 at 12:35:19AM +0000, Francis D. wrote:

On Mon, Nov 18, 2013 at 02:49:27PM -0500, Nam wrote:

Hi there,

I would like to see if it’s possible to get limit_conn and limit_req
working with the rewrite modules if statement.

Not according to the current documentation.

I suspect that patches will be welcome, if they fit the usual criteria.

Not really. Pathes to enable directives in if-in-location context
are not considered. Instead, directives should be able to work
with variables.

In case of limit_req / limit_conn, variables support is already
here. Whitelisting can be easily done with something like this:

map $whitelist $limit {
    default    $binary_remote_addr;
    1          "";
}

limit_req_zone $limit zone=one:10m rate=1r/s;

server {
    ...

    set $whitelist "";

    if (...) {
        set $whitelist 1;
    }

    limit_req one;

    ...
}

[…]


Maxim D.
http://nginx.org/en/donation.html