How to Install and Utilize Fail2ban on Debian 12

Fail2ban monitors log files for failed login attempts and temporarily blocks the IP address exhibiting frequent failures from accessing the host. This offers a robust defense against brute-force password-guessing attacks, making Fail2ban an invaluable tool for hosts exposed to the Internet.

The version of Fail2ban on Debian 12 is 1.0.2:

root@posti:~# fail2ban-client version
1.0.2

You can check if Fail2ban is running by using the command ping with fail2ban-client. A “pong” response indicates that the server is active:

root@posti:/etc/fail2ban# fail2ban-client ping
Server replied: pong
root@posti:/etc/fail2ban#

How it Works

Fail2ban compiles filters, actions, and monitored files into a jail. The distribution includes several jails, which need to be enabled to become functional. A filter specifies how authentication failures are detected, while an action outlines the process of banning and unbanning.

An IP is banned if, within the findtime, it triggers at least maxretry login failures. The ban persists for the bantime duration, after which the ban is lifted, allowing IP access again. Fail2ban supports both IPv4 and IPv6 protocols.

For additional details, refer to the documentation found in the directory /usr/share/doc/fail2ban/.

Setting Up Fail2ban

Debian GNU/Linux systems install Fail2ban by default with the SSHD jail enabled with reasonable settings found in /etc/fail2ban/jail.d/defaults-debian.conf. This is the only default enabled jail, others require manual activation.

If you merely need to monitor SSH logins and ban intruders, no further configuration is needed. However, Debian 12’s settings may not initialize Fail2ban properly, as rsyslog package is optional and may not be installed, thereby limiting logs to journald [wiki.debian.org/Rsyslog].

If using ISPConfig, Fail2ban works seamlessly because ISPConfig’s autoinstaller includes rsyslog, consistent with instructions in the ISPConfig Perfect server tutorial.

With rsyslog, log files are located in the /var/log/ directory, compatible with Fail2ban’s default configurations. If not installed, adjust Fail2ban’s setup to read logs from the systemd journal by setting the backend to systemd in jail.local like this:

[DEFAULT]
backend = systemd

Enabling a Jail

It’s advised to make all custom changes in .local files to prevent conflicts when distribution files are upgraded or modified by maintainers. [For detailed instructions, read /usr/share/doc/fail2ban/README.Debian.gz].

For example, to enable the pure-ftpd jail, add to /etc/fail2ban/jail.local (ensure file creation if it doesn’t exist):

[pure-ftpd]
enabled = true

Once modifications are done, apply changes by reloading the configurations:

systemctl reload fail2ban

You can verify the jail’s status with fail2ban-client:

root@posti:/etc/fail2ban# fail2ban-client status pure-ftpd
Status for the jail: pure-ftpd
|- Filter
|  |- Currently failed:	0
|  |- Total failed:	106
|  `- File list:	/var/log/syslog
`- Actions
   |- Currently banned:	0
   |- Total banned:	4
   `- Banned IP list:	
root@posti:/etc/fail2ban#

If only the “enabled” setting for a jail is in jail.local, remaining settings adhere to distribution defaults. Typically, these settings are sufficient. However, jail-specific configurations in jail.local can surpass default values when necessary.

For instance, modifying findtime, maxretry, and bantime for the pure-ftpd jail:

[pure-ftpd]
enabled = true
findtime = 2h
maxretry = 6
bantime = 1d

While Fail2ban-client displays times in seconds, configurations can use more accessible formats, like 10h instead of 36000 seconds. You can reference the “TIME ABBREVIATION FORMAT” section in man jail.conf for user-friendly time input specifications.

Fail2ban-client can also convert time formats:

# fail2ban-client --str2sec 1d3h7m
97620

Follow the Logs

Identify which jails to activate by monitoring logs generated by services running on the host. Log summarization tools like logwatch or pflogsumm can simplify this process, as parsing raw logs is labor-intensive.

Verify jail availability for running services by examining jail.conf.

Once logs reveal potential threats, take a closer look. For example, if a pflogsumm email summary includes entries similar to:

136   unknown[91.224.92.40]: SASL LOGIN authentication failed: UGFzc3...
136   hostname srv-91-224-92-40.serveroffer.net does not resolve to a...
123   unknown[193.32.162.23]: SASL LOGIN authentication failed: UGFzc...
123   hostname mail.whatami.co does not resolve to address 193.32.162.23

Here, IP 91.224.92.40 had 136 login failures under email authentication, suggesting Fail2ban didn’t intervene effectively. Delve into the Fail2ban logs for insight:

root@posti:/etc/apt/apt.conf.d# grep 91.224.92.40 /var/log/fail2ban.log | head
2024-02-18 00:01:38,718 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:01:38
2024-02-18 00:11:50,261 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:11:50
2024-02-18 00:21:54,337 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:21:54
2024-02-18 00:32:14,232 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:32:14
2024-02-18 00:42:37,921 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:42:37
2024-02-18 00:53:06,796 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 00:53:06
2024-02-18 01:03:35,293 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:03:35
2024-02-18 01:14:03,765 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:14:03
2024-02-18 01:24:24,628 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:24:24
2024-02-18 01:34:43,876 fail2ban.filter         [996]: INFO    [postfix-sasl] Found 91.224.92.40 - 2024-02-18 01:34:43
root@posti:/etc/apt/apt.conf.d#

This IP attempts access at approximately 10-minute intervals, detected by the postfix-sasl jail. Verify if the IP might belong to a legitimate host user with incorrect credentials saved on a device making regular attempts. Use geoiplookup to ascertain the IP’s originating country; it’s available from Debian packages geoip-database and geoip-bin. For instance:

$ geoiplookup 91.224.92.40
GeoIP Country Edition: LT, Lithuania

Examine the findtime of that jail to understand why the IP was not banned:

root@posti:/etc/apt/apt.conf.d# fail2ban-client get postfix-sasl findtime
600
root@posti:/etc/apt/apt.conf.d#

The attacker likely circumvented bans by exploiting the 10-minute findtime with prolonged intervals. Extend the findtime to cover longer attack periods, like 10 hours, with this addition to jail.local in the [postfix-sasl] section:

findtime = 10h

Reload Fail2ban for the changes to take effect:

root@posti:/etc/fail2ban# fail2ban-client get postfix-sasl findtime
36000
root@posti:/etc/fail2ban#

Persistent intruders adapt by resuming attacks post-ban. Extending bantime to retaliate can inadvertently affect legitimate users. Instead, use the recidive jail to counter repeat offenders with prolonged bans, like a week’s duration.

Consider this Logwatch report excerpt:

--------------------- pam_unix Begin ------------------------ 
 sshd:
    Authentication Failures:
       unknown (212.70.149.150): 59 Time(s)

Check the logs for the IP activity:

2024-02-21 03:42:39,121 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 03:42:38
2024-02-21 03:42:39,508 fail2ban.actions        [895]: NOTICE  [sshd] Ban 212.70.149.150
2024-02-21 03:52:38,386 fail2ban.actions        [895]: NOTICE  [sshd] Unban 212.70.149.150
2024-02-21 03:54:33,560 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 03:54:33
2024-02-21 03:54:35,364 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 03:54:35
2024-02-21 04:00:37,017 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 04:00:36
2024-02-21 04:00:39,021 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 04:00:38
2024-02-21 04:06:43,036 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 04:06:42
2024-02-21 04:06:45,039 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 04:06:44
2024-02-21 04:06:45,426 fail2ban.actions        [895]: NOTICE  [sshd] Ban 212.70.149.150
2024-02-21 04:16:44,302 fail2ban.actions        [895]: NOTICE  [sshd] Unban 212.70.149.150
2024-02-21 04:19:04,868 fail2ban.filter         [895]: INFO    [sshd] Found 212.70.149.150 - 2024-02-21 04:19:04

Fail2ban works effectively but opponents continue post-ban. The solution lies in activating the recidive jail with a reduced maxretry and extended bantime. Setting a 10-minute short ban, with severe penalties for repeat offenders, is advisable. Defaults from jail.conf (bantime: 1 week, findtime: 1 day) generally work well, but consider setting maxretry to 2 for quicker penalties. Add this to jail.local:

[recidive]
enabled = true
maxretry = 2

Extremely lengthy bans (over a week) may backfire, potentially affecting new IP holders. Hence, prudent ban durations safeguard against unintended consequences.

Troubleshooting

Fail2ban retains its state post-OS boot or restart, so bans last until bantime ends. Restarting helps in testing and troubleshooting configurations.

Test setups using Fail2ban’s test option:

fail2ban-server --test

To determine if an IP is banned, newer Fail2ban versions provide:

# fail2ban-client banned 43.131.9.186
[['recidive']]

Older versions lack this feature, requiring manual checks:

# fail2ban-client status recidive | tr " " "\n" | grep 43.163.219.232
43.163.219.232

Delve into Fail2ban logs for IP activity details:

root@posti:/etc/mysql# grep 43.131.9.186 /var/log/fail2ban.log | cut --characters=-80
2024-03-06 09:00:40,295 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:02:53,954 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:02:55,958 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:04:34,193 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:04:36,195 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:04:36,388 fail2ban.actions [3574846]: NOTICE  [sshd] Ban 43
2024-03-06 09:04:36,626 fail2ban.filter  [3574846]: INFO    [recidive] Fo
2024-03-06 09:14:35,180 fail2ban.actions [3574846]: NOTICE  [sshd] Unban
2024-03-06 09:15:10,073 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:16:55,919 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:16:58,522 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:18:44,972 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:20:30,018 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:20:30,499 fail2ban.actions [3574846]: NOTICE  [sshd] Ban 43
2024-03-06 09:20:30,620 fail2ban.filter  [3574846]: INFO    [recidive] Fo
2024-03-06 09:20:30,899 fail2ban.actions [3574846]: NOTICE  [recidive] Ba
2024-03-06 09:20:32,021 fail2ban.filter  [3574846]: INFO    [sshd] Found
2024-03-06 09:30:29,289 fail2ban.actions [3574846]: NOTICE  [sshd] Unban

For a comprehensive configuration dump, use highly verbose output:

# fail2ban-client -vvv -d

Whitelisting IP Addresses

If necessary, whitelist your own or trusted IPs to prevent unjust bans. Verify existing settings:

root@posti:~# fail2ban-client get sshd ignoreip
No IP address/network is ignored
root@posti:~

Instead of setting ignoreip per jail, configure it globally in the DEFAULT section to affect all. For instance, to avoid bans for an internal subnet, add this to jail.local:

[DEFAULT]
ignoreip = 92.237.123.96/27

The DEFAULT section can encompass global settings for all jails, like setting findtime = 10h.

Manual Banning

For testing, manually ban an IP using a short bantime jail to avoid self-lockout. For instance:

# fail2ban-client set sshd banip 8.8.4.4</>

If auto-banning fails, manually set bans in the recidive jail for troublesome IPs for an extended period, like a week:

# fail2ban-client set recidive banip 8.8.4.4

Banning a subnet requires CIDR notation:

fail2ban-client set recidive banip 5.188.87.0/24

Manual Unbanning

Before unbanning, address any persistent issues by reviewing logs and resolving misbehaviors:

# fail2ban-client set recidive unbanip 8.8.4.4

If an IP is blocked in several jails, unban it globally with:

# fail2ban-client unban 8.8.4.4

For full unblocking across all jails:

fail2ban-client unban --all

Conclusion

Fail2ban significantly mitigates password-guessing risks but can’t fully prevent hacking attempts. Enhanced security measures—for SSH, enforce SSH keys; for other services, implement multi-factor authentication—are strongly recommended.

Frequently Asked Questions (FAQs)

What is Fail2ban?

Fail2ban is software that protects servers against brute-force attacks by monitoring log files, identifying repeated failed login attempts, and blocking the offending IPs temporarily.

How does Fail2ban determine when to ban an IP address?

Fail2ban uses parameters such as findtime, maxretry, and bantime. If a specified number of login failures occur within a certain timeframe (findtime), the IP is banned for the specified bantime.

Can Fail2ban work without rsyslog?

Yes, Fail2ban can work without rsyslog by adjusting its configuration to read logs directly from the systemd journal, by setting the backend to systemd.

Why doesn’t Fail2ban block persistent attackers right away?

Persistent attackers may adjust their attempt frequency to avoid reaching the configured maxretry threshold within the findtime. Adjusting findtime and maxretry can enhance defense against such strategies.

What should I do if my IP gets banned accidentally?

You can whitelist your IP by adding it to the ignoreip setting in the DEFAULT section of your Fail2ban configuration.