I’ve recently had a flood of botnet-driven brute force attempts against my SMTP server. After struggling with some Fail2ban configuration issues, I’d gotten it working smoothly. However, this was a particularly persistent botnet, and as soon as the ban expired, I’d get more entry attempts. This is a problem; I want hackers to be thwarted, so I can’t set ban times too low; but I do not want to lock out my users if they legitimately forget a password. After putting up with my mailbox being flooded with Fail2ban reports, I decided to look into increasing times for subsequent bans. Fail2ban does not support this natively, so I had to look into other options.

The solution I came up with, after trying various complicated methods, is so simple that I feel stupid for not having done it in the first place. All I did was create a filter that parses Fail2ban’s own log, searching for bans. I then created a series of jails and set incrementing “maxretry” variables, with increased find and ban times.

The result of the following example is that, if a service on my server receives 5 failed password attempts in a day, the IP is banned for three hours. If this happens twice in a week, it is banned for a day. Thrice in a month, banned for a week, and so on. All of these values can be adjusted, and I’m still playing with them to find settings I like on my own server, but so far the system works brilliantly well.


First, create file: /etc/fail2ban/filter.d/f2b-loop.conf

# Fail2Ban configuration file for subsequent bans
before = common.conf
failregex = \]\s+Ban\s+<HOST>
ignoreregex = \[f2b-loop.*\]\s+Ban\s+<HOST>
# Author: Walter Heitman Jr.  http://blog.shanock.com


Now append/incorporate these entries into /etc/fail2ban/jail.local. Do not replace your existing file. Modify the values to your own preferences.

bantime  = 10800 ;3 hours
findtime  = 86400 ;1 day
maxretry = 5

enabled = true
filter = f2b-loop
bantime = 86400 ;1 day
findtime = 604800 ;1 week
logpath = /var/log/fail2ban.log
maxretry = 2

enabled = true
filter = f2b-loop
bantime	= 604800 ;1 week
findtime = 2592000 ;1 month
logpath = /var/log/fail2ban.log
maxretry = 3

enabled = true
filter = f2b-loop
bantime = 2592000 ;1 month
findtime = 15552000 ;6 months
logpath = /var/log/fail2ban.log
maxretry = 6

enabled = true
filter = f2b-loop
bantime = 15552000 ;6 months
findtime = 31536000 ;1 year
logpath = /var/log/fail2ban.log
maxretry = 9


You may add or remove jails, but the naming scheme must be maintained. The reason is that the filter ignores entries from [f2b-loop*] in order to avoid unintended interactions with itself. This solution was developed under Gentoo Linux, running Fail2ban version 0.9.0-r1, and may require modification for other distros and versions*. I have also set dbpurgeage=31536000 in fail2ban.conf; I don’t know if this makes a difference.

In addition to implementing these Fail2ban rules to deal with botnets, I have also incorporated blocklist.de information into an iptables block list using Florian Schaal’s helpful script.


* It has been brought to my attention that some distributions do not supply configuration files with a default “action=” parameter under “[default]”. You will need to add this, either to “[default]” or to each “[f2b-loop*]” jail.

Another reader pointed out that Fedora uses firewall-cmd instead of iptables to do its banning, but it is not capable of 1-year timeouts. The 5th loop in this example will have to be modified or removed. It may also be necessary to adjust the ignoreregex parameter.