fail2ban or How I Learned to Love netfilter

fail2ban or How I Learned to Love netfilter

If you have ports open to the internet you need to use Fail2ban. It has been around for a long time and it's pretty ubiquitous in Linux systems exposed to the public. This article is going to walk you through the process I use to setup fail2ban on the machines with ports open to the public.

The first step is to install the package:

sudo apt update
sudo apt install fail2ban

This should install and start the fail2ban service. You can check on it's status with the sudo systemctl status fail2ban command. Now that it's installed open up the configuration file and take a look.

less /etc/fail2ban/fail2ban.conf
less /etc/fail2ban/jail.conf

Now that you see the general idea of how the configuration works, the next step is to create a local copy of data that might get overwritten in an upgrade. The command below uses a bash shortcut to copy jail.conf to jail.local, for more information see my bash user's guide.

sudo cp /etc/fail2ban/jail.{conf,local}

Now for configuring the local jails. I am going to use SSH as an example, mainly due to how common SSH is and the fact that almost everyone needs to do something to stop brute force attacks on SSH*.

sudo vi /etc/fail2ban/jail.local

In this file you will want to configure some "Miscellaneous Options", should you find the need, the length of time an IP address has been blocked as well as the how far back in time to look for previous login attempts. I personally leave these settings at their default values.

bantime = 10m

findtime = 10m

Ten minutes for both, so any attempts from the same IP address over a 10 minute period will be counted against the total. Which brings us to:

maxretry = 5

This is the number of failed attempts before a ban is enacted. I sometimes set this value lower if the system will only be accessed by administrators and power users and higher if the users will be more of the general population. Like most configurable settings, this is something you will need to determine yourself and adjust as needed.

The next section is "Actions". I usually don't change any of these and configure emails sent to root to be forwarded to my user or the admin team's alias. You can take a look at the actions and see what the pre-configured options are. There is a short description above each and are fairly self-explanatory. Don't edit these unless you know what you are doing or are prepared to spend a non-trivial amount of time configuring them.

Finally - "Jails". This is where you define what happens for each service you want fail2ban protection on. Typically SSH is the first jail you will come to in the file, so lets take a look.


# To use more aggressive sshd modes set filter parameter "mode" in jail.local:
# normal (default), ddos, extra or aggressive (combines all).
# See "tests/files/logs/sshd" or "filter.d/sshd.conf" for usage example and details.
#mode   = normal
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

This jail is ready to be enabled as it is. I usually enable and add other setting changes in the /etc/fail2ban/jail.d directory so I an easily add and remove them but it is fine to do it in the jail.local file as well. In my case I typically run Debian and /etc/fail2ban/jail.d/defaults-debian.conf exists by default so I edit it to make these changes.

sudo vi /etc/fail2ban/jail.d/defaults-debian.conf

enabled = true

enabled = true

Pretty simple so far, let's get into something a bit more interesting.

I sometimes see a number of the same IP addresses getting banned over and over again. And I wondered if anyone else had the same problem, that's when I found this:

So now I have a jail that "permanently" blocks IP addresses once they are repeatedly caught by the SSH jail. The setup is a bit more complicated because we are adding something completely new to the fail2ban service and need to tell it what to do. In /etc/fail2ban/action.d we need to create a file named iptables-repeater.conf and place the following in it, elevated privileges (sudo) will be required.

# Fail2ban configuration file
# Author: Phil Hagen <>


# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
actionstart = iptables -N fail2ban-REPEAT-<name>
              iptables -A fail2ban-REPEAT-<name> -j RETURN
              iptables -I INPUT -j fail2ban-REPEAT-<name>
              # set up from the static file
              cat /etc/fail2ban/ip.blocklist.<name> |grep -v ^\s*#|awk '{print $1}' | while read IP; do iptables -I fail2ban-REPEAT-<name> 1 -s $IP -j DROP; done

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
actionstop = iptables -D INPUT -j fail2ban-REPEAT-<name>
             iptables -F fail2ban-REPEAT-<name>
             iptables -X fail2ban-REPEAT-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
actioncheck = iptables -n -L INPUT | grep -q fail2ban-REPEAT-<name>

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
# Values:  CMD
actionban = iptables -I fail2ban-REPEAT-<name> 1 -s <ip> -j DROP
            # also put into the static file to re-populate after a restart
            ! grep -Fq <ip> /etc/fail2ban/ip.blocklist.<name> && echo "<ip> # fail2ban/$( date '+%%Y-%%m-%%d %%T' ): auto-add for repeat offender" >> /etc/fail2ban/ip.blocklist.<name>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    <ip>  IP address
#          <failures>  number of failures
#          <time>  unix timestamp of the ban time
# Values:  CMD
actionunban = /bin/true


# Defaut name of the chain
name = REPEAT

Now in the jail.local file we took a look at above, add the following just below the SSH section. Like the rest of the edits, this one requires root permissions to edit.

filter   = sshd
action   = iptables-repeater[name=ssh]
           sendmail-whois[name=SSH-repeater, dest=root, sender=root]
logpath  = %(sshd_log)s
maxretry = 21
findtime = 31536000
bantime  = 31536000

As you can see, it sets the bantime & findtime to a very big number (it's actually the number of seconds in a year). I've made a change to the jail above from the blog post I got it from, specifically the logpath has been changed.

To apply the changes run the following on systemd systems

sudo systemctl restart fail2ban

That's it, you may want to check out the article where I go over fail2ban-client and what to do when you need to unban an IP address or want to manually ban one.