Multiple matching limit_req

I would like to apply rate limiting based on 3 different criteria.

  1. CDN should have rate limit of 100 r/s (identified by $http_host)
  2. Whitelisted bots should have a rate limit of 15 r/s (identified by
    $http_user_agent)
  3. All other users should have a rate limit of 5 r/s

The rules should be applied in the above order of preference. If a rule
matches two criteria, the earlier one should get applied. How can I
ensure
this?

I have tried the following config, but it is always rate limited to 5
r/s,
irrespective of the order of the limit_req entries.

map $http_host $limit_cdn {
default ‘’;
cdn-cname.mydomain.com” $binary_remote_addr;
}
map $http_user_agent $limit_bot {
default ‘’;
~*(google|bing) $binary_remote_addr;
}

limit_req_zone $limit_cdn zone=limit_cdn:1m rate=100r/s;
limit_req_zone $limit_bot zone=limit_bot:1m rate=15r/s;
limit_req_zone $binary_remote_addr zone=limit_all:10m rate=5r/s;

limit_req zone=limit_all burst=12;
limit_req zone=limit_bot burst=50 nodelay;
limit_req zone=limit_cdn burst=200 nodelay;

On Fri, Jan 09, 2015 at 07:18:37PM +0530, Joyce B. wrote:

Hi there,

I would like to apply rate limiting based on 3 different criteria.

  1. CDN should have rate limit of 100 r/s (identified by $http_host)
  2. Whitelisted bots should have a rate limit of 15 r/s (identified by
    $http_user_agent)
  3. All other users should have a rate limit of 5 r/s

The rules should be applied in the above order of preference. If a rule
matches two criteria, the earlier one should get applied. How can I ensure
this?

You can’t.

All limits that match are applied, which means that the most restrictive
one is seen.

What you can do is change your specification with that in mind, and
choose your keys so that they are empty when you do not want the limit
to apply.

map $http_host $limit_cdn {
default ‘’;
cdn-cname.mydomain.com” $binary_remote_addr;
}
map $http_user_agent $limit_bot {
default ‘’;
~*(google|bing) $binary_remote_addr;
}

Add the following variables with names that more closely resemble what
they
are intended to do:

map $limit_cdn $limit_bot_not_cdn {
default ‘’;
‘’ $limit_bot;
}

map $limit_cdn$limit_bot $limit_not_bot_not_cdn {
‘’ $binary_remote_addr;
default ‘’;
}

And use those variables as the keys that you actually mean:

limit_req_zone $limit_cdn zone=limit_cdn:1m rate=100r/s;

Leave that one as-is.

limit_req_zone $limit_bot zone=limit_bot:1m rate=15r/s;

Change that to be

limit_req_zone $limit_bot_not_cdn zone=limit_bot:1m rate=15r/s;

limit_req_zone $binary_remote_addr zone=limit_all:10m rate=5r/s;

Change that to be

limit_req_zone $limit_not_bot_not_cdn zone=limit_all:10m rate=5r/s;

limit_req zone=limit_all burst=12;
limit_req zone=limit_bot burst=50 nodelay;
limit_req zone=limit_cdn burst=200 nodelay;

and the rest should work as you want.

(Unless you use “return”.)

f

Francis D. [email protected]

Hi Francis,

Thank you for the clever solution. I have updated my server
configuration
with the change and it is now working.