Every Linux server sees brute-force attempts on port 22/tcp within minutes of booting — botnets are constantly trying SSH password guesses. Fail2ban reads log files, detects failed login attempts and automatically bans the attacker IP at the firewall. This guide covers installing and tailoring Fail2ban from scratch.

Installation

# Ubuntu / Debian
sudo apt update && sudo apt install -y fail2ban

# RHEL / AlmaLinux / Rocky
sudo dnf install -y epel-release && sudo dnf install -y fail2ban

sudo systemctl enable --now fail2ban
sudo systemctl status fail2ban

Base Configuration: jail.local

Never edit jail.conf directly — package upgrades overwrite it. Create a jail.local instead; Fail2ban merges both files.

# /etc/fail2ban/jail.local
[DEFAULT]
# Global settings
bantime = 1h
findtime = 10m
maxretry = 5
banaction = iptables-multiport
backend = systemd

# Never ban your own IP
ignoreip = 127.0.0.1/8 ::1 YOUR_HOME_IP/32

# Email notifications
destemail = admin@example.com
sender = fail2ban@example.com
mta = sendmail
action = %(action_mwl)s

[sshd]
enabled = true
port = ssh
maxretry = 3
bantime = 24h

Managing Jails

sudo systemctl reload fail2ban

# List all jails
sudo fail2ban-client status

# Status of the SSH jail
sudo fail2ban-client status sshd

# Unban an IP
sudo fail2ban-client set sshd unbanip 1.2.3.4

# Manually ban an IP
sudo fail2ban-client set sshd banip 1.2.3.4

Protecting Nginx Auth Endpoints

Not just SSH; Nginx basic auth, WordPress wp-login and Postfix SASL can all be protected. You can also write your own jails.

# inside /etc/fail2ban/jail.local
[nginx-http-auth]
enabled = true
filter = nginx-http-auth
port = http,https
logpath = /var/log/nginx/error.log
maxretry = 5

[nginx-botsearch]
enabled = true
filter = nginx-botsearch
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 24h

[wordpress]
enabled = true
filter = wordpress
port = http,https
logpath = /var/log/nginx/access.log
maxretry = 3
# /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php HTTP.*" 200
            ^<HOST> .* "POST /xmlrpc.php HTTP.*"
ignoreregex =

Permanent Ban List (recidive jail)

If the same IP is banned repeatedly, the recidive jail applies a much longer ban. Ideal for chronic attackers.

[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 5

Logs and Stats

# Live log
sudo tail -f /var/log/fail2ban.log

# Number of IPs banned in the last 24 hours
sudo grep "Ban " /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | wc -l

# Most frequently banned sources (geo analysis via whois)
sudo grep "Ban " /var/log/fail2ban.log | awk '{print $NF}' | sort -u | head -20

Extra Hardening

  • Set PasswordAuthentication no — key-only SSH login
  • Move SSH off port 22 (for example to 22022)
  • AllowUsers admin@1.2.3.0/24 for IP-based restrictions
  • Default deny policy with UFW or iptables
  • Ship Fail2ban logs to Grafana/Loki to watch attack trends

Conclusion

Fail2ban is the first guard on your Linux server's doorstep. It takes 10 minutes to configure and silently blocks thousands of attempts per year. Fail2ban + UFW + key-only SSH is the backbone of server hardening, and something the KEYDAL team installs on every managed server by default.

VPS security hardening

Full hardening with Fail2ban, UFW, SSH key-only auth and anti-scanner rules Contact us

WhatsApp