Secure Debian 12 with Fail2ban and nftables
In a previous article, we covered how to protect your Debian 12 server with nftables, where we configured a custom SSH port and locked down access to your server. As a follow-up, this guide will show you how to set up Fail2ban to add an additional layer of security by automatically banning IP addresses that attempt too many failed login attempts.
Fail2ban is a popular intrusion prevention software that monitors log files (or in our case, the systemd journal) for suspicious activity and dynamically updates firewall rules to block offending IP addresses. In this tutorial, we’ll be using Fail2ban with systemd journal as the backend (instead of the traditional syslog) and nftables as the firewall backend.
Prerequisites
Before we begin, make sure you have the following in place:
- A Debian 12 server with SSH access.
- Familiarity with the nftables configuration we set up previously.
- A valid email address to receive security notifications (optional).
Step 1: Install Fail2ban and Required Packages
Start by installing Fail2ban and the Python systemd module:
apt install fail2ban python3-systemd
Step 2: Configure Fail2ban’s Default Settings
Create the /etc/fail2ban/fail2ban.local
file and add the following configuration:
[DEFAULT]
allowipv6 = auto
This enables IPv6 support and applies the default settings.
Step 3: Configure Fail2ban’s Jail Settings
Next, open the /etc/fail2ban/jail.local
file and add the following configuration:
[DEFAULT]
# Debian 12 has no log files, just journalctl
backend = systemd
# Destination email for action that sends you an email
destemail = alerts@your-domain.com
# Sender email. Warning: not all actions take this into account. Make sure to test if you rely on this
sender = fail2ban@your-domain.com
# Default action. Will block user and send you an email with whois content and log lines.
action = %(action_mwl)s
# ignoreip can be a list of IP addresses, CIDR masks, or DNs hosts. Fail2ban
# # will not ban a host which matches an address in this list.
ignoreip = 127.0.0.1/8 ::1/128
# configure nftables
banaction = nftables-multiport
chain = input
# regular banning
bantime = 24h
findtime = 600
maxretry = 3
# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
bantime.increment = true
# "bantime.rndtime" is the max number of seconds using for mixing with random time
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
bantime.rndtime = 30m
# "bantime.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
bantime.maxtime = 60d
# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
# default value of factor is 1 and with default value of formula, the ban time
# grows by 1, 2, 4, 8, 16 ...
bantime.factor = 2
# purge database entries after
dbpurgeage = 30d
[sshd]
mode = aggressive
enabled = true
backend = systemd
port = 3344
maxretry = 3
This configuration sets up the following:
- Tells Fail2ban to use the systemd journal as the backend instead of traditional log files.
- Configures the email settings for notifications.
- Sets the default action to block the user and send an email with details.
- Ignores connections from localhost and IPv6 localhost.
- Configures nftables as the firewall backend and sets the input chain.
- Defines the banning settings, such as duration, retry attempts, and exponential ban time increase.
Note that the port = 3344
setting in the [sshd]
jail section matches the custom SSH port we configured in the previous article.
Step 4: Restart Fail2ban and Check the Status
Restart the Fail2ban service and check its status:
systemctl restart fail2ban
systemctl status fail2ban
You should see the service running and active.
Step 5: Test the Fail2ban Configuration
To test the Fail2ban configuration, you can try to brute-force the SSH service by running the following command from a different machine:
ssh -p 3344 invalid_user@your-server-ip
Repeat this command a few times (more than the maxretry
setting) to trigger the ban. You can then check the status of the sshd
jail:
fail2ban-client status sshd
This should show the currently banned IP addresses.
Step 6 (Optional): Activate the “Recidive” Jail
If you want to add an extra layer of protection against repeat offenders, you can activate the “recidive” jail. This jail will monitor the Fail2ban log file and ban IP addresses that have been banned multiple times.
To activate the “recidive” jail, add the following configuration to the /etc/fail2ban/jail.local
file:
[recidive]
backend = auto
logpath = /var/log/fail2ban.log
enabled = true
maxretry = 2
banaction = nftables-allports
This configuration tells Fail2ban to use the log file (instead of the journal) to monitor for repeat offenders, and it bans them on all ports using the nftables-allports
action.
After making this change, restart Fail2ban again:
systemctl restart fail2ban
And that’s it! You now have Fail2ban set up and working in conjunction with the nftables firewall configuration from the previous article. This provides a robust security setup for your Debian 12 server.