Skip to content

How to secure Nginx with Fail2ban from botnet attack

Last updated on August 4, 2020

If you faced botnet or you have any other suspicious activity on the server, you should take some actions to prevent it as soon as possible.

So there’s some steps to block the attack:

  1. Configure Nginx to return 4xx error on request
  2. Log all bad bots to custom config
  3. Install and configure Fail2ban
  4. Make a Fail2ban jail to monitor and ban every bad bot from custom config
  5. Profit!

Reject request if header is not present or wrong

Add to your sites config the following:

location / {
if ($http_referer) {
return 437; }

Modify /etc/nginx/nginx.conf, add:
* this will block only 437 errors and log in custom access_bad.log

map $status $loggable {
404 0; # ignore page not found (404).
499 0; # ignore canceled/closed requests.
437 1; # block botnet
~^[45] 0; # all other requests with status starting with 4 or 5.
default 0;
# log the bad requests: 
access_log /var/log/nginx/access_bad.log combined if=$loggable;
# all other requests:
access_log /var/log/nginx/access.log combined;

Install and configure Fail2ban jail

First, we need to update our local package index and then we can use apt to download and install the package:

sudo apt-get update
sudo apt-get install fail2ban

Configure Fail2Ban with your Service Settings

The fail2ban service keeps its configuration files in the /etc/fail2ban directory. There is a file with defaults called jail.conf.

Individual Jail Settings

Finally, we get to the portion of the configuration file that deals with individual services. These are specified by the section headers, like [ssh].

We need to copy this to a file called jail.local for Fail2Ban to find it.

cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Configure defaults in jail.local

Open up the new Fail2Ban configuration file:

You can see the default section below:


# "ignoreip" can be an IP address, a CIDR mask or a DNS host. Fail2ban will not
# ban a host which matches an address in this list. Several addresses can be
# defined using space separator.
ignoreip =

# Override /etc/fail2ban/jail.d/00-firewalld.conf:
banaction = iptables-multiport

# "bantime" is the number of seconds that a host is banned.
bantime  = 600

# A host is banned if it has generated "maxretry" during the last "findtime"
# seconds.
findtime  = 600

# "maxretry" is the number of failures before a host get banned.
maxretry = 5

Configure Fail2ban For ssh

Although you can add this parameters in the global jail.local file, it is a good practice to create seperate jail files for each of the services we want to protect with Fail2Ban.

So lets create a new jail for SSH with the vi editor.

vi /etc/fail2ban/jail.d/sshd.local

In the above file, add the following lines of code:

enabled = true
port = ssh
action = iptables-multiport
logpath = /var/log/secure
maxretry = 5
bantime = 600
Restart Fail2Ban

After making any changes to the Fail2Ban config, always be sure to restart Fail2Ban.

systemctl restart fail2ban

You can see the rules that fail2ban puts in effect within the IP table:

iptables -L -n
Check Fail2Ban Status

Use fail2ban-client command to query the overall status of the Fail2Ban jails.

fail2ban-client status

You can also query a specific jail status using the following command:

fail2ban-client status sshd

Make a Fail2ban jail to monitor and ban every bad bot from custom config

Add following to bottom of the config file
bantime – how long it will stay banned
maxretry – how many times it will request the server before it will be banned


enabled = true
port = http,https
filter = nginx-badbots
failregex = ^<HOST> -.*"(GET|POST|HEAD).*HTTP.*" 437
ignoreregex =
backend = auto
logpath = /var/log/nginx/access_bad.log
bantime = 259200
maxretry= 1
/etc/init.d/fail2ban restart

Check nginx config and restart service if syntax is ok

nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
/etc/init.d/nginx reload

Now let’s check if everything is working:

fail2ban-client status nginx-badbots
Status for the jail: nginx-badbots
|- Filter
| |- Currently failed: 0
| |- Total failed: 536
| `- File list: /var/log/nginx/access_bad.log
`- Actions
|- Currently banned: 531
|- Total banned: 531
`- Banned IP list:

Everything works like a charm 🙂

Published inAutomationLinuxNginxSecurity