Nginx – Block direct port 80 access on default IP using iptables

centos6csfddosiptablesnginx

I am using nginx with cloudflare in front of my sites to protect them from layer 7 attacks but now some attackers found this new way and they are daily attacking my default IP directly with layer 7 attack instead of attacking the sites. I am returning 444 response to them when they open default page on direct ip address but still the attacks are too big so they are making all the site/server unavailable for few minutes and sometime for longer period depending on attack making Nginx busy.

So i wanted to ask if it's possible to disable port 80 access on default ip without affecting my other sites and services? These attacks are too big that that my log file for default vhost is becoming 1GB in less thn 1 hour so even returning 444 isn't working thats why i think blocking it at firewall level will be better?

Any suggestion how to achieve this with iptables?

I am using CentOS 6.9 with Ngiinx 1.13.

Anymore ideas? Still waiting!

Best Answer

You could setup iptables rules to only allow CloudFlare IPs to reach your Nginx instance on port 80 etc. This can be achieved by first creating an ipset with a list of CloudFlare's IPv4 ranges (available at https://www.cloudflare.com/ips-v4), then applying the appropriate iptables rules to utilise the set.

Something like the below should work:

ipset -N cloudflare nethash

ipset -q -A cloudflare A.B.C.D/M
... [ repeat above for each entry in CF ips-v4 file ]

iptables -A INPUT -p tcp --dport 80 -m set --match-set cloudflare src -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP

Further Nginx Trick using the CloudFlare Ray-ID Header

For each site that does have CloudFlare in front of it, you can also apply this trick into Nginx. It effectively checks for the existence of the CloudFlare CF-Ray header, in the expected format. If this does NOT exist, 444 is returned (an immediate drop of the request).

server {
    listen A.B.C.D:80;
    server_name _;
    if ($http_cf_ray !~ '^[0-9a-f]{16}-[A-Z]{3}$') { return 444; }
...

I would imagine you could also disable logging at this point to further mitigate any excessive log noise (untested):

    if ($http_cf_ray !~ '^[0-9a-f]{16}-[A-Z]{3}$') { access_log off; error_log off; return 444; }
Related Topic