42.2 fail2ban: Automated Banning of Brute-Force Attackers
Right, let’s talk about fail2ban. If you’ve ever glanced at your auth log (/var/log/auth.log on Debian/Ubuntu, /var/log/secure on Red Hat derivatives) and seen a relentless, mind-numbing stream of “Failed password for root from 1.2.3.4”, you’ve met the enemy. It’s not a sophisticated APT; it’s a script kiddie or, more likely, a bot running a dictionary attack. It’s the technological equivalent of a zombie shuffling against your door, and fail2ban is the automated plank of wood with a nail in it that you use to bonk it on the head. Repeatedly.
The concept is gloriously simple: fail2ban watches log files for patterns that signal a brute-force attack, like multiple failed login attempts. When it sees too many failures from a single IP address within a configured time window, it says, “Alright, that’s enough of you,” and adds a rule to the local firewall (like iptables or nftables) to block that IP for a designated ban time. It’s an automated, intelligent bouncer for your server.
The Core Anatomy: Jails, Filters, and Actions
The magic—and the initial configuration headache—lies in understanding its three key components: jails, filters, and actions. Don’t let the names fool you; it’s not as complex as it sounds.
A filter is a regex pattern that tells fail2ban what to look for in the log file. The default one for SSH is clever enough to catch both password failures and invalid user attempts.
An action is what fail2ban does when a filter is triggered enough times. The default action is to block the IP using iptables/nftables, but it can be configured to send you an email, post to a Slack channel, or anything else you can script.
A jail is the container that brings a filter and an action together. It defines which log file to watch, which filter to use, and which action to take. It also contains the crucial parameters: maxretry (how many failures trigger a ban) and findtime (the time window in which those failures must occur).
Your First (and Most Important) Jail: SSHD
The SSH jail is the one you absolutely need. It’s usually enabled by default, but let’s not leave it to chance. The main configuration file is /etc/fail2ban/jail.local (create it if it doesn’t exist). You use this file to override settings from the default jail.conf because, and I cannot stress this enough, you do not edit jail.conf. Your package manager will happily obliterate your changes on an update. jail.local is for your overrides.
Here’s a robust starting point for your SSH jail:
# /etc/fail2ban/jail.local
[DEFAULT]
# Ban hosts for one hour (-1 means forever, which is overkill)
bantime = 3600
# Override /etc/fail2ban/jail.d/00-firewalld.conf if it exists.
# This forces fail2ban to use iptables, which is more universally understood.
banaction = iptables-multiport
[sshd]
enabled = true
# Whoa there! 5 failures in 10 minutes is plenty.
maxretry = 5
findtime = 600
# This is the port SSH is actually listening on. Change if you're not on 22.
port = 22
After saving this, restart the fail2ban service: sudo systemctl restart fail2ban. Check its status to see if your jail is active: sudo fail2ban-client status sshd. It should proudly report the number of currently banned IPs.
Beyond SSH: Protecting Other Services
SSH is the big one, but fail2ban is a versatile beast. You can and should protect other services. Getting a web login brute-forced? Set up a jail for NGINX or Apache. Let’s create one for a hypothetical web admin panel at /admin/login.
First, you need a filter. Create a new file: /etc/fail2ban/filter.d/nginx-admin.conf
# /etc/fail2ban/filter.d/nginx-admin.conf
[Definition]
failregex = ^<HOST> -.*POST /admin/login.* 403$
ignoreregex =
This filter catches any IP (<HOST>) that sends a POST request to your admin login and gets a 403 Forbidden error back—a classic sign of a failed authentication attempt.
Now, enable the jail by adding it to your jail.local:
# /etc/fail2ban/jail.local
[nginx-admin]
enabled = true
port = http,https
maxretry = 3
findtime = 300
bantime = 86400 # A full day for web bots, they're peskier.
logpath = /var/log/nginx/access.log
The Inevitable “Oh Crap” Moment: Unbanning Yourself
You will eventually lock yourself out. It’s a rite of passage. You fat-finger a password five times while SSH’d from your coffee shop’s WiFi, and suddenly your connection dies. The solution isn’t to panic; it’s to have a plan.
Option 1 (The Pro Move): Use fail2ban-client from another server you have access to.
ssh user@your-server.com 'sudo fail2ban-client set sshd unbanip 192.168.1.42'
Option 2 (The Console Move): If you have physical or out-of-band (like DigitalOcean’s console) access, log in and unban yourself directly:
sudo fail2ban-client unban 192.168.1.42
Option 3 (The “I’m already locked out” Move): If all else fails, and you have console access, you can temporarily stop fail2ban to clear all bans: sudo systemctl stop fail2ban. But be quick! Restart it (sudo systemctl start fail2ban) as soon as you’ve logged back in.
Pitfalls and Pro Tips
- Don’t Go Ban-Happy: A
bantimeof-1(permanent) is usually a bad idea. It fills your firewall ruleset and can cause performance issues. Let bans expire. - Check Your Logs: The number one reason a jail doesn’t work is because the
logpathis wrong. Always double-check where your service is actually logging. Usetail -f /path/to/logand generate a failure to confirm. - The IgnoreIP Setting: This is your most important setting. Add your personal IP, your office’s IP range, and any trusted networks to
ignoreipin the[DEFAULT]section. Banning your entire company’s CIDR block is a fantastic way to get a funny story and a stern talking-to. - It’s Not a Silver Bullet: fail2ban is fantastic against brute-force bots. It is useless against a targeted attack with a correct password, or attacks that use a different IP for every request (like a botnet). For real security, you need strong passwords, key-based authentication for SSH, and keeping software updated.
fail2ban is the workhorse of server defense. It’s not glamorous, but it’s ruthlessly effective at its one job: making the low-hanging fruit of your server taste like nails. And that’s exactly what you want.