Fail2Ban doesn’t actually block IP addresses; it configures the system’s firewall (like iptables or nftables) to drop packets from malicious IPs.
Let’s get Fail2Ban set up to protect your SSH server from brute-force attacks.
Here’s what a typical SSH brute-force attempt looks like from the server’s perspective:
Aug 15 10:00:01 your-server sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 54321 ssh2
Aug 15 10:00:02 your-server sshd[12346]: Failed password for root from 192.168.1.100 port 54322 ssh2
Aug 15 10:00:03 your-server sshd[12347]: Failed password for admin from 192.168.1.100 port 54323 ssh2
Aug 15 10:00:04 your-server sshd[12348]: Failed password for user from 192.168.1.100 port 54324 ssh2
Aug 15 10:00:05 your-server sshd[12349]: Failed password for invalid user test from 192.168.1.100 port 54325 ssh2
Notice the repeated "Failed password" entries from the same IP address (192.168.1.100) within a short period. Fail2Ban watches for these patterns.
First, install Fail2Ban. On Debian/Ubuntu:
sudo apt update && sudo apt install fail2ban -y
On CentOS/RHEL:
sudo yum install epel-release -y
sudo yum install fail2ban -y
Once installed, the service usually starts automatically. Check its status:
sudo systemctl status fail2ban
The primary configuration file is /etc/fail2ban/jail.conf. Never edit this file directly. Updates can overwrite your changes. Instead, create a local override file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Inside jail.local, you’ll find a [DEFAULT] section. These are global settings that apply to all jails unless overridden. Key parameters here:
bantime: How long an IP is banned. A good starting point is1h(1 hour). For more aggressive blocking,24hor even1w(1 week).findtime: The time window within whichmaxretrymust be met for an IP to be banned.10m(10 minutes) is common.maxretry: The number of failed attempts allowed from an IP withinfindtimebefore it’s banned.5is a reasonable default.
Scroll down to the [sshd] section. This is the specific jail for SSH. Ensure it’s enabled by setting enabled = true.
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log # Or /var/log/secure on CentOS/RHEL
maxretry = 5
bantime = 1h
findtime = 10m
The logpath is crucial. It tells Fail2Ban where to find the SSH logs. Common paths are /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (CentOS/RHEL). If you’ve customized your SSH daemon’s log file, update this accordingly.
After saving jail.local, reload Fail2Ban for the changes to take effect:
sudo systemctl reload fail2ban
You can check the status of your jails and banned IPs with:
sudo fail2ban-client status
And for a specific jail like sshd:
sudo fail2ban-client status sshd
This will show you how many IPs are currently banned and from which jail.
Common Issues and Fixes:
-
Fail2Ban Service Not Running:
- Diagnosis:
sudo systemctl status fail2banshowsinactive (dead). - Cause: Service failed to start, likely due to a misconfiguration or missing dependency.
- Fix:
sudo systemctl start fail2ban && sudo systemctl enable fail2ban. Check logs for specific errors:sudo journalctl -u fail2ban. - Why it works: Explicitly starts the service and configures it to launch on boot.
- Diagnosis:
-
No IPs Being Banned:
- Diagnosis:
sudo fail2ban-client status sshdshows0 banned IPs. - Cause 1: Incorrect
logpathinjail.local. Fail2Ban can’t see the failed login attempts. - Fix 1: Verify the SSH log file path (e.g.,
/var/log/auth.logor/var/log/secure). Tail the file (sudo tail -f /var/log/auth.log) during a test login failure to confirm it’s logging correctly. Updatelogpathinjail.localif necessary. - Why it works: Points Fail2Ban to the actual log file where login events are recorded.
- Cause 2: Incorrect
filteroraction. The filter defines the regex to match log lines, and the action defines how to block. Defaults are usually correct for SSH. - Fix 2: Ensure
filter = sshdand the corresponding filter definition in/etc/fail2ban/filter.d/sshd.confmatches your log format. For most systems, default filters are fine. Checkaction = %(action_mwl)sor similar injail.localfor the[sshd]section. - Why it works: Ensures Fail2Ban is using the correct rules to identify bad behavior and the correct commands to execute firewall rules.
- Cause 3:
findtimeis too long ormaxretryis too high. The attacker isn’t hitting the threshold within the window. - Fix 3: Temporarily lower
findtimeto5mandmaxretryto3injail.localfor testing. - Why it works: Makes the banning condition easier to meet, allowing you to verify functionality. Remember to revert to desired values.
- Diagnosis:
-
Banned IPs Not Being Unbanned:
- Diagnosis: IPs remain in
sudo fail2ban-client status sshdoutput long afterbantimeshould have expired. - Cause: The
bantimeis set to0or a negative value, or thefail2ban-clientservice is not running or has errors preventing it from cleaning up. - Fix: Ensure
bantimeis a positive duration (e.g.,1h,24h). If it’s set to0, it means "never ban." Checksudo systemctl status fail2banandsudo journalctl -u fail2banfor any errors related to unbanning actions. Restarting Fail2Ban (sudo systemctl restart fail2ban) can sometimes clear stale bans. - Why it works:
bantime = 0is an explicit configuration to disable banning. A restart ensures the service re-evaluates current bans and their expiry.
- Diagnosis: IPs remain in
-
Accidentally Banning Yourself:
- Diagnosis: You can’t SSH into your server.
sudo fail2ban-client status sshdshows your IP is banned. - Cause: Your own IP address has triggered the
maxretrylimit. This can happen with incorrect passwords, VPN IP changes, or network glitches. - Fix: Use the
fail2ban-client set <jailname> unbanip <ip_address>command from a different IP address or console access. For example:sudo fail2ban-client set sshd unbanip 192.168.1.100. You can also add your trusted IP toignoreipinjail.local:ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24. - Why it works: Explicitly tells Fail2Ban to remove the ban for a specific IP or to never monitor it.
- Diagnosis: You can’t SSH into your server.
-
Firewall Conflicts:
- Diagnosis: Fail2Ban reports IPs as banned, but you can still ping or SSH from them.
- Cause: Fail2Ban’s actions (e.g.,
iptablesrules) are being overridden or are not being applied correctly by your firewall management system. - Fix: Ensure Fail2Ban’s firewall actions are allowed to run. Check your firewall configuration (e.g.,
/etc/iptables/rules.v4,firewalldservices,ufwrules). Fail2Ban typically usesiptablesornftables. If usingfirewalld, ensure thefail2banservice is enabled and that Fail2Ban is configured to usefirewalldactions (often handled automatically iffirewalldis present). Restartingfirewalldafterfail2ban reloadcan help:sudo systemctl restart firewalld. - Why it works: Confirms that the firewall rules Fail2Ban creates are persistent and not being immediately removed by another management tool.
After successfully configuring and reloading Fail2Ban, the next thing you’ll likely want to investigate is how to monitor Fail2Ban’s activity more closely, perhaps by sending email notifications when an IP is banned.