Permanently Ban Repeat Offenders With Fail2Ban

label_outlinechat_bubble_outline Comment

You might have seen one of our last posts on setting up Fail2Ban with Plesk and CentOS. This post is being made in response to people asking how they could permanently ban those hosts that repeatedly get banned. This can be very helpful in reducing the emails that are received from Fail2Ban.


There is a built in system for Fail2Ban to check the default log and then put in place a lengthier ban based on the attempts logged. The problem with this approach is that those logs are rotated and eventually discarded. Although Fail2Ban will search through archived logs it obviously can’t search through those that have been deleted. The other problem with this solution is that those IP’s aren’t stored anywhere other than iptables which means that when the server or Fail2Ban service is restarted the table will be wiped clean. Of course Fail2Ban will re-apply the iptables rule if those IP addresses remain in the syslog files (so long as they haven’t been rotated to deletion).

The approach that we provide creates another chain specifically for those banned IP addresses and a file to store them.

Modify F2B Defaults

nano /etc/fail2ban/fail2ban.conf

Around line 24:

loglevel = 3

Around line 34:

logtarget = /var/log/fail2ban.log

Modify Log Rotation

nano /etc/logrotate.d/fail2ban

Replace everything with:

/var/log/fail2ban.log {
    rotate 13
    create 0600 root root
        /usr/bin/fail2ban-client set logtarget /var/log/fail2ban.log 2> /dev/null || true

What we have done here is that we’ve told log rotate to rotate this log every month and delete the old logs after 13 months. This is because our find time (which we’ll talk about later) is defined at 1 year. If the find time is only 1 year we will never need to have logs files beyond that period of time because the IP’s will be saved in our IP block list.

Add Repeat Offender Jail

nano /etc/fail2ban/jail.local

At the very end of the file place this bit of code:


enabled  = true
filter   = repeatoffender
action   = repeatoffender[name=repeatoffender]
logpath  = /var/log/fail2ban*
maxretry = 10
findtime = 31536000
bantime  = -1

What we have done is we have created a new filter which monitors the log that we created in the previous step. We assigned it a filter and we also assigned it a new action. We have set the max attempts to 10 times (you can change this number as you wish) and we have set the find time to 31536000 which is 1 year in seconds. Of course you could change this number to anything that you’d like as well. If you lengthen it YOU MUST change the log rotation deletion period as well. We have set the ban time to -1, which equals forever.

Create the Fail2Ban Filter

nano /etc/fail2ban/filter.d/repeatoffender.conf

Place this in the file:

#Fail2Ban configuration file
# Author: WireFlare
# This filter monitors the fail2ban log file, and permanently
# bans the ip addresses of persistent attackers.
# As of this version this ban only works with iptables.

_jailname = repeatoffender
failregex = fail2ban.actions:\s+WARNING\s+\[(?:.*)\]\s+Ban\s+<HOST>
ignoreregex = fail2ban.actions:\s+WARNING\s+\[%(_jailname)s\]\s+Ban\s+<HOST>

Here we have defined the rules in order to catch the repeat offenders.

Create the Fail2Ban Action

nano /etc/fail2ban/action.d/repeatoffender.conf

# Fail2Ban configuration file
# Author: WireFlare


before = iptables-blocktype.conf


# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
actionstart = iptables -N fail2ban-<name>
              iptables -A fail2ban-<name> -j RETURN
              iptables -I <chain> -p <protocol> -j fail2ban-<name>
              # Establish chain and blocks for saved IPs
              iptables -N fail2ban-ip-blocklist
              iptables -A fail2ban-ip-blocklist -j RETURN
              iptables -I <chain> -p <protocol> -j fail2ban-ip-blocklist
              cat /etc/fail2ban/ip.blocklist.<name> |grep -v ^\s*#|awk '{print $1}' | while read IP; do iptables -I fail2ban-ip-blocklist 1 -s $IP -j REJECT --reject-with icmp-port-unreachable; done

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
actionstop = iptables -D <chain> -p <protocol> -j fail2ban-<name>
             iptables -F fail2ban-<name>
             iptables -X fail2ban-<name>
             # Remove chain and blocks for saved IPs to prevent duplicates on service restart
             iptables -D <chain> -p <protocol> -j fail2ban-ip-blocklist
             iptables -F fail2ban-ip-blocklist
             iptables -X fail2ban-ip-blocklist

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
actioncheck = iptables -n -L <chain> | grep -q 'fail2ban-<name>[ \t]'

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionban = VERIFY="<ip>*"
            ADD="<ip>        # fail2ban/$( date '+%%Y-%%m-%%d %%T' ): Perma-Banned"
            grep -q "$VERIFY" "$FILE" || iptables -I fail2ban-<name>  1 -s <ip> -j DROP
            grep -q "$VERIFY" "$FILE" || echo "$ADD" >> "$FILE"

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
actionunban = # Do nothing becasuse their IP is in the blocklist file

# To manually unban from the ip blocklist file run this command:
# Be warned that if the ip is in log rotated files it must be whitelisted
# sed -i '/^<ip>/d' /etc/fail2ban/ip.blocklist.repeatoffender


# Default name of the chain
name = default

# Option:  protocol
# Notes.:  internally used by config reader for interpolations.
# Values:  [ tcp | udp | icmp | all ] Default: tcp
protocol = tcp

# Option:  chain
# Notes    specifies the iptables chain to which the fail2ban rules should be
#          added
# Values:  STRING  Default: INPUT
chain = INPUT

So what we have done here is the following:

In “actionstart” we’ve created the additional iptables chain. We’ve actually created 2 new chains, one will be for recently blocked perma-banned IP’s and the other will be for those that are stored in the IP Block List. We’ve also created the command to read from the IP Block List and apply those iptables entries into the ip-blocklist chain.

In “actionstop” we have added the ip-blocklist chain in addition to the original chain in order to remove the chain from iptables in the event of fail2ban being restarted. If this wasn’t there we would get duplicates.

In “actionban” we have established variables. VERIFY will be used to verify if the IP address is already in the list of blacklisted IP addresses. You might ask yourself “Well if we are banning them forever why would we need to check the file for the IP? They should never touch the server again!”. The answer is simple; if the server or Fail2Ban is restarted Fail2Ban will re-scan those log files. If the match is verified again (the required number of hits exists in the non-deleted logs) the actionban will trigger. This would normally create another entry in the IP Block List file as well as create another block on the firewall in addition to the block established by the IP Block List file on actionstart. FILE is used to define the location and name of the file to store the IP’s. We then use grep to verify the existence of the IP in the file and write to iptables to block the IP. Secondly we write to the IP Block List file the IP address to be blocked.

In “actionunban” we have eliminated the command because we don’t want to ever un-ban them.

Removal of IP’s

We have also added a small command to remove the IP address from the IP Block List file should you ever need to. Simply replace <ip> with the IP address that you wish to remove.

sed -i '/^<ip>/d' /etc/fail2ban/ip.blocklist.repeatoffender

Note that you’ll also have to whitelist the IP and remove it from iptables otherwise it will (1) not be un-blocked or (2) be re-blocked on the next restart.

Once you are done re-start the service with the following command:

/usr/bin/fail2ban-client reload

At the request of some users we’ve put together a removal script that should clear out an IP from all of the files. This is how we do it:


Place the following in the file:


sed -i "\|$1|d" /etc/fail2ban/ip.blocklist.repeatoffender
echo "$1 removed from Repeat Offender Blocklist"

sed -i "\|$1|d" /var/log/fail2ban.log
echo "$1 removed from Current Fail2Ban Log"

sed -i "\|$1|d" /var/log/fail2ban.log-*
echo "$1 removed from Rotated Fail2Ban Logs"

Save and exit with Ctlr-X. Give it permission to execute:

chmod +x

Run the command with the IP after the command for example:


From all of us at WireFlare we ask that you help others find the answers they are looking for. Please leave a comment or share this post!


Blog Bio Picture For Todd

I'm the President of WireFlare. I have a passion for creativity, online business and internet security. I strive to create a community that empowers people to be themselves. I'm an adventurist, fun loving and caring. Find me hiking in places most people don't dare to go!

Get a free consultation today!