Forum: NGINX limit_req and limit_conn in rewrite modules if statement

2974d09ac2541e892966b762aad84943?d=identicon&s=25 Nam (Guest)
on 2013-11-18 20:49
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,244781,244781#msg-244781
2974d09ac2541e892966b762aad84943?d=identicon&s=25 Nam (Guest)
on 2013-11-18 21:58
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,244781,244783#msg-244783
34011bc56457235a2caa5ed1d4a29f3c?d=identicon&s=25 Jonathan Matthews (Guest)
on 2013-11-18 22:06
(Received via mailing list)
On 18 November 2013 20:57, Nam <nginx-forum@nginx.us> 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
2974d09ac2541e892966b762aad84943?d=identicon&s=25 Nam (Guest)
on 2013-11-19 00:24
(Received via mailing list)
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:
http://forum.nginx.org/read.php?2,244781,244789#msg-244789
36a8284995fa0fb82e6aa2bede32adac?d=identicon&s=25 Francis Daly (Guest)
on 2013-11-19 01:35
(Received via mailing list)
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 Daly        francis@daoine.org
A8108a0961c6087c43cda32c8616dcba?d=identicon&s=25 Maxim Dounin (Guest)
on 2013-11-19 03:45
(Received via mailing list)
Hello!

On Tue, Nov 19, 2013 at 12:35:19AM +0000, Francis Daly 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 Dounin
http://nginx.org/en/donation.html
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.