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 is 1h (1 hour). For more aggressive blocking, 24h or even 1w (1 week).
  • findtime: The time window within which maxretry must be met for an IP to be banned. 10m (10 minutes) is common.
  • maxretry: The number of failed attempts allowed from an IP within findtime before it’s banned. 5 is 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:

  1. Fail2Ban Service Not Running:

    • Diagnosis: sudo systemctl status fail2ban shows inactive (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.
  2. No IPs Being Banned:

    • Diagnosis: sudo fail2ban-client status sshd shows 0 banned IPs.
    • Cause 1: Incorrect logpath in jail.local. Fail2Ban can’t see the failed login attempts.
    • Fix 1: Verify the SSH log file path (e.g., /var/log/auth.log or /var/log/secure). Tail the file (sudo tail -f /var/log/auth.log) during a test login failure to confirm it’s logging correctly. Update logpath in jail.local if necessary.
    • Why it works: Points Fail2Ban to the actual log file where login events are recorded.
    • Cause 2: Incorrect filter or action. 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 = sshd and the corresponding filter definition in /etc/fail2ban/filter.d/sshd.conf matches your log format. For most systems, default filters are fine. Check action = %(action_mwl)s or similar in jail.local for 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: findtime is too long or maxretry is too high. The attacker isn’t hitting the threshold within the window.
    • Fix 3: Temporarily lower findtime to 5m and maxretry to 3 in jail.local for testing.
    • Why it works: Makes the banning condition easier to meet, allowing you to verify functionality. Remember to revert to desired values.
  3. Banned IPs Not Being Unbanned:

    • Diagnosis: IPs remain in sudo fail2ban-client status sshd output long after bantime should have expired.
    • Cause: The bantime is set to 0 or a negative value, or the fail2ban-client service is not running or has errors preventing it from cleaning up.
    • Fix: Ensure bantime is a positive duration (e.g., 1h, 24h). If it’s set to 0, it means "never ban." Check sudo systemctl status fail2ban and sudo journalctl -u fail2ban for any errors related to unbanning actions. Restarting Fail2Ban (sudo systemctl restart fail2ban) can sometimes clear stale bans.
    • Why it works: bantime = 0 is an explicit configuration to disable banning. A restart ensures the service re-evaluates current bans and their expiry.
  4. Accidentally Banning Yourself:

    • Diagnosis: You can’t SSH into your server. sudo fail2ban-client status sshd shows your IP is banned.
    • Cause: Your own IP address has triggered the maxretry limit. 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 to ignoreip in jail.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.
  5. Firewall Conflicts:

    • Diagnosis: Fail2Ban reports IPs as banned, but you can still ping or SSH from them.
    • Cause: Fail2Ban’s actions (e.g., iptables rules) 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, firewalld services, ufw rules). Fail2Ban typically uses iptables or nftables. If using firewalld, ensure the fail2ban service is enabled and that Fail2Ban is configured to use firewalld actions (often handled automatically if firewalld is present). Restarting firewalld after fail2ban reload can 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.

Want structured learning?

Take the full Ssh course →