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:

  1. jail.conf and jail.local: The main configuration file is /etc/fail2ban/jail.conf. Never edit this file directly. Instead, create /etc/fail2ban/jail.local. Fail2Ban reads .local files after .conf files, so your local settings override the defaults.

  2. [DEFAULT] Section: This section sets global parameters.

    • bantime: How long an IP is banned. Default is often 10m (10 minutes). For more robust protection, 1h (1 hour) or even 1d (1 day) is better.
    • findtime: The window of time during which Fail2Ban counts failed attempts. Default is 10m.
    • maxretry: The number of failures within findtime before an IP is banned. Default is often 5.
    • banaction: The action Fail2Ban takes to ban an IP. The default is usually iptables-multiport.
    • ignoreip: A list of IPs to never ban. Crucial for your own IP address or internal networks.

    A good starting point in jail.local might look like this:

    [DEFAULT]
    bantime = 1h
    findtime = 10m
    maxretry = 3
    ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24
    

    This 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/24 will never be banned.

  3. [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 = 1h
    
    • enabled = true: Activates this jail.
    • port: The service port (e.g., ssh or 22).
    • 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.
    • maxretry and bantime: You can override the [DEFAULT] settings here for specific jails.
  4. Restart Fail2Ban: After making changes to jail.local, you must restart the Fail2Ban service:

    sudo systemctl restart fail2ban
    

    You 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.

Want structured learning?

Take the full Cdk course →