Just spin up a brand-new Linux VPS and open the public SSH port, then check your authentication logs: hundreds of automated bots from all over the world are hammering away, attempting to brute-force the root password every minute. If you rely on a simple password, your server could be compromised at any moment.
Fail2ban is the classic, go-to tool to eliminate this headache. It continuously scans system log files, detects IPs showing signs of repeated failed login attempts, and automatically creates firewall rules (using iptables or nftables) to ban those IPs on the spot.
1. Quick Start: Install and Enable SSH Protection in 5 Minutes
To get started quickly on Ubuntu/Debian or CentOS/AlmaLinux, simply follow these steps in order.
Installing Fail2ban
On Ubuntu or Debian:
sudo apt update
sudo apt install -y fail2ban
On RHEL/AlmaLinux/Rocky Linux (requires enabling the EPEL repository first):
sudo dnf install -y epel-release
sudo dnf install -y fail2ban
Creating a Dedicated Configuration File
A golden rule with Fail2ban is to never directly edit the original /etc/fail2ban/jail.conf file, as package updates will overwrite it. Instead, create a jail.local file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
Quick SSH Protection Setup
Open /etc/fail2ban/jail.local using your preferred text editor:
sudo nano /etc/fail2ban/jail.local
Locate the [sshd] block or append the following configuration to the end of the file:
[sshd]
enabled = true
port = ssh
logpath = %(sshd_log)s
backend = %(syslog_backend)s
maxretry = 5
findtime = 600
bantime = 3600
Starting the Service
Save the file and run the following commands to start Fail2ban:
sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban
Verify whether the SSH protection jail is active:
sudo fail2ban-client status sshd
2. Deep Dive: Core Fail2ban Configuration Parameters
Once you have this basic shield in place, it helps to understand the underlying mechanics so you can fine-tune them for your specific environment.
Default Parameters (DEFAULT Section)
Inside the jail.local file, the most critical parameters include:
- ignoreip: A list of trusted IPs that should never be banned. For example, your static office IP, home IP, or internal subnets (
127.0.0.1/8 ::1 192.168.1.0/24). - bantime: The duration (in seconds) an offending IP remains banned. For example,
3600equals 1 hour. To ban permanently, you can set a negative number (-1). - findtime: The time window (in seconds) in which Fail2ban tallies failed login attempts.
- maxretry: The maximum number of failed attempts permitted within
findtimebefore an IP is blacklisted.
For example: With findtime = 600 and maxretry = 3, if an IP fails SSH authentication 3 times within 10 minutes, it is immediately banned for the duration defined by bantime.
Understanding Jails and Filters
Fail2ban operates on two primary components:
- Filter: Located in
/etc/fail2ban/filter.d/, containing regular expressions (regex) designed to match failed authentication patterns in log files. - Jail: Pairs a Filter with an Action (such as blocking traffic via iptables/nftables or sending email alerts) applied to a specific service.
3. Advanced: Extending Protection to Nginx and Web Servers
Beyond safeguarding SSH, Fail2ban is exceptionally effective at stopping directory traversal vulnerability scans and brute-force attacks against administrative login portals (such as wp-login.php on WordPress).
Blocking Malicious URL Scanning on Nginx
Open /etc/fail2ban/jail.local and configure an additional jail to block repeated queries probing for sensitive files that trigger 404/403 HTTP status codes:
[nginx-botsearch]
enabled = true
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 300
bantime = 86400
Blocking Brute-Force Attacks on WordPress / Web App Login Pages
Create a custom filter to catch rapid POST requests targeted at authentication endpoints. Create the file /etc/fail2ban/filter.d/nginx-login.conf:
[Definition]
failregex = ^<HOST> -.* "POST /wp-login.php HTTP/.*" 200
^<HOST> -.* "POST /login HTTP/.*" 200
ignoreregex =
Next, add the corresponding jail block to /etc/fail2ban/jail.local:
[nginx-login]
enabled = true
port = http,https
filter = nginx-login
logpath = /var/log/nginx/access.log
maxretry = 5
findtime = 600
bantime = 7200
Reload the configuration so the new jails take effect immediately:
sudo fail2ban-client reload
4. Administration and Practical Production Tips
After managing over 10 Linux VPSs for three years, I’ve learned that thorough testing before pushing to production is essential. I once had a colleague mistype their VPN/SSH password, and Fail2ban locked out our entire office IP during peak business hours simply because someone forgot to add it to the whitelist.
Essential Daily Management Commands
View active jails and the count of banned IPs:
sudo fail2ban-client status
Inspect detailed information and currently banned IPs for the sshd jail:
sudo fail2ban-client status sshd
If you or a teammate accidentally get banned, unban the IP immediately using:
sudo fail2ban-client set sshd unbanip 203.0.113.45
Inspect the Fail2ban activity log directly for troubleshooting:
sudo tail -f /var/log/fail2ban.log
Battle-Tested Best Practices
- Always whitelist your office and personal IPs: Add your static IP or subnet to
ignoreipbefore enabling any jail with an aggressivebantime. - Be cautious when changing SSH ports: If you switch the default SSH port from 22 to something like 2222, remember to update the
port = 2222line in the[sshd]section ofjail.local. Otherwise, Fail2ban will block port 22 while leaving the new port completely unprotected. - Test your regex before enabling: Use Fail2ban’s built-in testing utility to verify that your filter matches log entries accurately before running it in production:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-login.conf
Mastering Fail2ban gives your system a proactive defense layer, filtering out up to 99% of automated botnet scans with minimal server overhead.

