Fail2Ban doesn’t actually block brute-force attacks; it scans log files for patterns indicating brute-force attempts and then uses the system’s firewall to temporarily ban the offending IP addresses.
Let’s see Fail2Ban in action. Imagine an SSH brute-force attempt. We’ll simulate it, then configure Fail2Ban to catch it.
First, let’s look at SSH logs. On a typical Linux system, failed SSH login attempts show up in /var/log/auth.log (or /var/log/secure on RHEL-based systems).
tail /var/log/auth.log
You’d see lines like this for each failed attempt:
Oct 26 10:30:01 myserver sshd[12345]: Failed password for invalid user admin from 192.168.1.100 port 54321 ssh2
Oct 26 10:30:05 myserver sshd[12345]: Failed password for root from 192.168.1.100 port 54321 ssh2
Oct 26 10:30:09 myserver sshd[12345]: Connection closed by 192.168.1.100 port 54321 [preauth]
Fail2Ban works by reading these log files. It uses regular expressions (regex) to identify patterns that signify a brute-force attack. When a specific IP address generates too many of these patterns within a defined time window, Fail2Ban triggers a firewall rule to block that IP.
Here’s the core configuration:
-
jail.confandjail.local: The main configuration file is/etc/fail2ban/jail.conf. Never edit this file directly. Instead, create/etc/fail2ban/jail.local. Fail2Ban reads.localfiles after.conffiles, so your local settings override the defaults. -
[DEFAULT]Section: This section sets global parameters.bantime: How long an IP is banned. Default is often10m(10 minutes). For more robust protection,1h(1 hour) or even1d(1 day) is better.findtime: The window of time during which Fail2Ban counts failed attempts. Default is10m.maxretry: The number of failures withinfindtimebefore an IP is banned. Default is often5.banaction: The action Fail2Ban takes to ban an IP. The default is usuallyiptables-multiport.ignoreip: A list of IPs to never ban. Crucial for your own IP address or internal networks.
A good starting point in
jail.localmight look like this:[DEFAULT] bantime = 1h findtime = 10m maxretry = 3 ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24This means an IP will be banned for 1 hour if it fails to log in 3 times within a 10-minute window. Your local network
192.168.1.0/24will never be banned. -
[jail]Sections: These define specific services Fail2Ban should monitor. The most common is SSH.To enable SSH protection, add or uncomment this in
jail.local:[sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log # Or /var/log/secure for RHEL/CentOS maxretry = 3 bantime = 1henabled = true: Activates this jail.port: The service port (e.g.,sshor22).filter: Points to a filter definition file in/etc/fail2ban/filter.d/(e.g.,sshd.conf). This file contains the regex to match log entries.logpath: The log file to monitor for this service.maxretryandbantime: You can override the[DEFAULT]settings here for specific jails.
-
Restart Fail2Ban: After making changes to
jail.local, you must restart the Fail2Ban service:sudo systemctl restart fail2banYou can check its status:
sudo systemctl status fail2ban
Now, if an IP address repeatedly tries to SSH into your server and fails, Fail2Ban will detect it. Let’s say 1.2.3.4 tries to log in 5 times within 10 minutes.
Fail2Ban’s sshd filter uses regex to find lines like "Failed password for…" in auth.log. If it finds 3 such lines from 1.2.3.4 within findtime (10 minutes), it will execute the banaction (likely iptables-multiport). This action adds an iptables rule to block all incoming traffic from 1.2.3.4 to the specified ports for the bantime (1 hour).
You can check currently banned IPs with:
sudo fail2ban-client status sshd
This will show you which IPs are currently banned for the sshd jail. To unban an IP manually (use with caution):
sudo fail2ban-client set sshd unbanip 1.2.3.4
The most common mistake people make is not creating jail.local, or not restarting the service. Another is forgetting to add their own IP to ignoreip, leading to accidental self-lockout.
If you’re using a cloud provider with a security group or network ACL, Fail2Ban’s iptables rules will work in addition to those. If the IP is blocked at the cloud provider level, it won’t even reach your server to be seen by iptables or Fail2Ban.
The next thing you’ll likely encounter is needing to protect other services, like your web server (Apache/Nginx) or mail server (Postfix/Dovecot), by enabling and configuring their respective jails in jail.local.