Every server I deploy gets brute-force attempted within hours. SSH, HTTP auth, FTP, doesn't matter. The internet is full of bots scanning entire IP ranges 24/7 and they will find you.
fail2ban is the lazy dev's answer to this. It reads your logs, spots repeated failures, and tells your firewall to drop the offender. No fancy IDS, no SIEM, just a simple Python script that watches log files and bans IPs.
Here is how I set it up on every server I run.
Install
sudo apt install fail2banThat's it. On Debian/Ubuntu it ships with reasonable defaults. On RHEL/CentOS: sudo yum install fail2ban or sudo dnf install fail2ban.
How It Works
fail2ban has three concepts: filters, actions, and jails.
A filter is a regex that matches a failure in a log file. An action is what happens when someone gets banned ( usually iptables drop ). A jail ties a filter to an action with parameters like how many retries before banning and how long the ban lasts.
The default install comes with a bunch of pre-made filters for common services. You can see them all in /etc/fail2ban/filter.d/.
The SSH Jail ( the only one you need to start with )
fail2ban ships with an SSH jail ready to go. You just enable it. Create a local override file ( never edit the main config directly, it gets overwritten on updates ):
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localThen find the [sshd] section and make sure it looks like this:
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600Here is what those params mean:
maxretry = 3: ban after 3 failed attempts
bantime = 3600: ban lasts 1 hour ( in seconds )
findtime = 600: count failures within a 10-minute window
If you want to be more aggressive ( and I usually am ), set bantime to 86400 for a 24-hour ban, or even -1 for a permanent ban.
Restart and Verify
sudo systemctl restart fail2ban
sudo fail2ban-client statusYou should see something like:
Status
|- Number of jail: 1
`- Jail list: sshdCheck the jail details:
sudo fail2ban-client status sshdThis shows you how many IPs are currently banned, the file list, and the filter in use. Give it a day and you'll see banned IPs pile up.
Adding More Jails
Most web servers get hammered on HTTP auth too. Here is a jail for nginx:
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 3
bantime = 3600The filter file /etc/fail2ban/filter.d/nginx-http-auth.conf already exists in the default install. Same idea for Apache, Postfix, Dovecot, and a bunch of others — just look in filter.d/ and enable the corresponding jail.
For custom applications, write your own filter. It's just a regex:
# /etc/fail2ban/filter.d/myapp.conf
[Definition]
failregex = ^%(__prefix_line)s.*Authentication failure.*from <HOST>
ignoreregex =Then create a jail that uses it:
[myapp]
enabled = true
filter = myapp
logpath = /var/log/myapp/auth.log
maxretry = 5
bantime = 7200Whitelist Your IP
Before you go banning everything in sight, whitelist yourself. In jail.local find the ignoreip line:
ignoreip = 127.0.0.1/8 ::1 YOUR_STATIC_IPYou really don't want to lock yourself out of your own server. Ask me how I know.
Checking Bans and Unbanning
List all banned IPs:
sudo fail2ban-client status sshdUnban a specific IP ( maybe you locked yourself out ):
sudo fail2ban-client set sshd unbanip 1.2.3.4Check the iptables rules fail2ban created:
sudo iptables -L f2b-sshd -vfail2ban creates its own chain ( f2b-sshd, f2b-nginx-http-auth, etc. ) so it doesn't mess with your existing rules.
Ban Times That Scale
I like to make bans longer for repeat offenders. fail2ban supports this with bantime.increment:
[DEFAULT]
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 604800First ban: 1 hour. Second ban: 2 hours. Third: 4 hours. And so on, up to a week. Persistent bots get locked out for days while you sleep.
Conclusion
fail2ban is one of those install-and-forget tools that quietly does its job. Set it up once, whitelist your IP, and let it deal with the bots. It won't stop a determined attacker but it stops 99% of the automated noise that fills up your logs.
The source is on GitHub: https://github.com/fail2ban/fail2ban :)