As Linux system administrators, we face thousands of automated bots every day, tirelessly knocking at our SSH doors, admin panels, and web services. Ignoring logs full of failed login attempts is asking for trouble. This is where Fail2Ban steps in — a tool as old as time (in IT terms), yet still irreplaceable, provided you know how to configure it properly.
The Nature of Brute-Force Attacks in 2024
Modern attacks are no longer just simple 'admin/admin' scripts. They're distributed botnets capable of rotating through hundreds of IP addresses to evade standard blocking thresholds. If your server is visible on the public internet, I can guarantee that someone is trying to guess your SSH password at this very moment. Fail2Ban acts as an intermediary layer between your service logs and the system firewall (iptables, nftables), dynamically responding to anomalies.
The Foundation: Installation and jail.local
Rule number one: Never edit /etc/fail2ban/jail.conf. It gets overwritten during package updates. Always create your own configuration file jail.local.
# Installation on Debian/Ubuntu
sudo apt update && sudo apt install fail2ban -y
# Creating the configuration file
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
In the jail.local file we should define global parameters that will be inherited by individual "jails":
[DEFAULT]
# Ignore my home IP address (critical!)
ignoreip = 127.0.0.1/8 ::1 192.168.1.100
# Ban duration (longer is better)
bantime = 1h
# Time window for counting attempts
findtime = 10m
# Maximum number of failures allowed
maxretry = 5
# Using nftables instead of iptables (modern standard)
banaction = nftables-multiport
SSH Hardening: The First Line of Defence
SSH is the most common target. Even if you use RSA/ED25519 keys, it's worth blocking bots to prevent them from wasting your CPU resources on authentication processes.
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 24h
Note the bantime = 24h. For SSH, I recommend an aggressive approach — if someone has failed 3 times within 10 minutes, they're probably not one of your employees.
Practice: Nginx and Apache Configuration: Fighting Vulnerability Scanners
Jail: The Heart of the System
Bots frequently scan web servers looking for files like .env, wp-login.php, or config.php. We can easily catch this by monitoring 404 or 403 errors.
For Nginx:
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
filter = nginx-botsearch
maxretry = 2
Custom Filters: When the Standard Isn't Enough
The true power of Fail2Ban lies in its Regex filters. If your application logs login errors in a specific way, create a filter in /etc/fail2ban/filter.d/my-app.conf:
[Definition] failregex = ^<HOST> - .* "POST /login .* 401 ignoreregex =
This simple pattern will capture all login attempts (POST) that resulted in a 401 (Unauthorized) response code.
Summary and Monitoring
Fail2Ban is not 'set and forget'. Check the status of your jails once a week: fail2ban-client status sshd. You'll see a list of currently banned IP addresses and general statistics. Remember, security is a process, and Fail2Ban is one of the most important cogs in your machine.