3

I have some "deny" rules before the request limit config. If a blocked user (by the deny rules) is ddossing the site he still triggers the request limit and therefore creates thousands of log entries. Why? I expected that it will not go past the deny rules.

    include        /etc/nginx/blacklist.conf;
    limit_req zone=limit burst=3 nodelay;

The log shows a forbidden error and right after that hundreds of request limitation errors. That repeats over and over again.

2 Answers 2

1

When nginx processes a request, it goes through several phases. Among them : preaccess and access phases. Preaccess is typically where limit_req works while access is where the allow/deny directives work. This means rate limiting is done before IP filtering if both directives are declared in the same context.

So if your will is to try to get some fail2ban alike process (given your other question return code 444) working directly in nginx using native directives, that's simply not possible by nature.

13
  • Thanks for the explanation. That is really sad. The main issue is indeed a fail2ban thing. We use CloudFlare and therefore can't use iptables to ban users, we use the CloudFlare API for that. When a DDos is incoming then fail2ban will use CloudFlare to ban the API, but it takes about a minute until the ban has fully applied, in this time thousands of requests still come through. Now the issue is that fail2ban goes through all of them and displays a "already banned" message. It takes a long time to go thourh them and therefore fail2ban takes a long time until it bans the next ip.
    – TheNiceGuy
    May 3, 2015 at 10:30
  • So we basically need a way to make sure that the log does not contain thousands of the "request limit exceeded" error for the same ip, otherwise that stops fail2ban from doing its job. Do you have any idea how we can do this? Tried to figure something out the last 2 days but nothing does work. Thank you very much!
    – TheNiceGuy
    May 3, 2015 at 10:32
  • @Michael In this case drop the allow/deny directives since this is cloudflare's job. Set some relevant overall limit_con. I don't know what kind of business you are hosting though but that's very unlikely you would see thousands of connections from the same legitimate IP (mobile phone APs included). Set a proprer limit_conn_status code to indicate you have forbidden excessive connections (for instance code 429 : Too Many Requests). Now if you are under DDoS and not DoS the best thing you can do is scale out. May 3, 2015 at 16:56
  • Sadly just setting a connection limit won't help us. Yesterday we hat 37Million requests coming in, generating 34TB of traffic. The log files are enourmes, thousands of different IPs with thousands of entries. We need a way to make sure that there is only one "request limit exceeded" entry for each IP, not a thousand, otherwise fail2ban will not keep up.
    – TheNiceGuy
    May 3, 2015 at 17:08
  • @Michael You can't fight DDoS at the web server level with only fail2ban as your weapon. Look at cloudflare's IUAM mode. Effective DDoS mitigation does not start at layer 7. May 3, 2015 at 17:18
0

This issue is a bit old, but for anyone having this issue, the best solution I found for this case is to use a map with an if instead of the deny rules (although I try to avoid using ifs in nginx), because like Xavier Lucas said:

rate limiting is done before IP filtering

You can change your blacklist.conf file from:

deny 1.2.3.4;

to:

1.2.3.4 0;

Create a file whitelist.conf:

if ( $whitelist = 0 ) {
    return 403;
}

Then, in nginx.conf, include a map that whitelists every ip, except the ones in blacklist.conf:

http {
    geo $whitelist {
        /etc/nginx/blacklist.conf;
        default 1;
    }

    ...
}

Finally, also in nginx.conf, add before every server directive the whitelist.conf file:

server {
    server_name ...;
    listen 443 ssl;

    include /etc/nginx/whitelist.conf;

    ssl_certificate       /etc/ssl/bundle.crt;
    ssl_certificate_key   /etc/ssl/server.key;

    ...
}

...

The requests from the blacklisted ips will be returned immediatelly and won't be logged in the error logs file.

You can also stop the requests from those ips from being logged in the access logs file with:

access_log /path/to/file if=$whitelist; 

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .