How to configure fail2ban to protect SSH

Fail2ban is a tool that protects your server against brute force attacks by monitoring system logs and automatically blocking IP addresses that show malicious behavior. This guide explains how to install and configure fail2ban to protect the SSH service.

How It Works

Fail2ban analyzes log files looking for patterns of failed authentication attempts. When an IP exceeds the allowed number of attempts within a time period, fail2ban adds a firewall rule to temporarily block that IP.

Prerequisites

  • Root or sudo access to the server
  • Server running Ubuntu/Debian or AlmaLinux/CentOS/RHEL

Step 1: Install fail2ban

Ubuntu / Debian

sudo apt update
sudo apt install fail2ban -y

AlmaLinux / CentOS / RHEL

sudo dnf install epel-release -y
sudo dnf install fail2ban -y

Step 2: Configure fail2ban

Fail2ban uses configuration files in /etc/fail2ban/. Never edit the original files (jail.conf, fail2ban.conf) as they get overwritten during updates. Instead, create .local files that take priority.

Create the local configuration file

sudo nano /etc/fail2ban/jail.local

Add the following configuration:

[DEFAULT]
# Ban time in seconds (1 hour)
bantime = 3600

# Time window to count failed attempts (10 minutes)
findtime = 600

# Number of failed attempts before banning
maxretry = 5

# Ignore local and trusted IPs (space-separated)
ignoreip = 127.0.0.1/8 ::1

# Default action: block with iptables
banaction = iptables-multiport

# Email for notifications (optional)
# destemail = admin@yourdomain.com
# sender = fail2ban@yourdomain.com
# action = %(action_mwl)s

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600

Note: If using AlmaLinux/CentOS/RHEL, change the log path:

logpath = /var/log/secure

Configuration with custom SSH port

If you changed the default SSH port (for example, to 2222), modify the port line:

[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600

Configuration with progressive banning

For bans that increase with each repeat offense, add:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600

[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
bantime = 604800
findtime = 86400
maxretry = 3

This configuration bans for one week (604800 seconds) IPs that have been banned 3 times in the last 24 hours.

Step 3: Start and enable fail2ban

sudo systemctl start fail2ban
sudo systemctl enable fail2ban

Verify the service is running:

sudo systemctl status fail2ban

Step 4: Verify the configuration

View active jails status

sudo fail2ban-client status

Expected output:

Status
|- Number of jail:      1
`- Jail list:   sshd

View SSH jail details

sudo fail2ban-client status sshd

Expected output:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  |- Total failed:     5
|  `- File list:        /var/log/auth.log
`- Actions
   |- Currently banned: 1
   |- Total banned:     2
   `- Banned IP list:   192.168.1.100

View firewall rules

sudo iptables -L -n | grep -A 10 fail2ban

Managing fail2ban

Unban an IP manually

sudo fail2ban-client set sshd unbanip 192.168.1.100

Ban an IP manually

sudo fail2ban-client set sshd banip 192.168.1.100

Reload configuration

After modifying configuration files:

sudo fail2ban-client reload

View fail2ban log

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

Additional recommended configurations

Protect other services

You can add jails for other services in /etc/fail2ban/jail.local:

# Protect Apache
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/*error.log
maxretry = 3
bantime = 3600

# Protect Nginx
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/*error.log
maxretry = 3
bantime = 3600

# Protect Postfix
[postfix]
enabled = true
port = smtp,465,submission
filter = postfix
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600

# Protect Dovecot
[dovecot]
enabled = true
port = pop3,pop3s,imap,imaps
filter = dovecot
logpath = /var/log/mail.log
maxretry = 3
bantime = 3600

Use nftables instead of iptables

On modern systems using nftables:

[DEFAULT]
banaction = nftables-multiport

Configure email notifications

To receive notifications when an IP is banned:

[DEFAULT]
destemail = admin@yourdomain.com
sender = fail2ban@yourdomain.com
mta = sendmail
action = %(action_mwl)s

Troubleshooting

Fail2ban is not banning IPs

  • Verify the log path is correct:
# Ubuntu/Debian
ls -la /var/log/auth.log

# AlmaLinux/CentOS
ls -la /var/log/secure
  • Confirm the filter detects failed attempts:
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
  • Check the fail2ban log:
sudo tail -50 /var/log/fail2ban.log

Service won't start

  • Check for syntax errors in configuration:
sudo fail2ban-client -t
  • Check system logs:
sudo journalctl -u fail2ban -n 50

I banned myself

If you have physical or console access to the server:

sudo fail2ban-client set sshd unbanip YOUR_IP

If you don't have access, wait for the configured bantime or access through another method (KVM console, IPMI, provider panel).

To prevent this, add your IP to the ignore list:

[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_STATIC_IP

IPs get unbanned after restart

By default, fail2ban doesn't persist bans between restarts. To enable persistence, add:

[DEFAULT]
banaction = iptables-multiport
banaction_allports = iptables-allports

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
# Save bans to database
backend = systemd

Or create a script that restores bans from /var/lib/fail2ban/fail2ban.sqlite3.

Best Practices

  1. Don't ban for too long: A bantime of 1-24 hours is sufficient for most attacks.
  2. Add your IPs to ignoreip: Avoid accidentally banning yourself.
  3. Monitor the logs: Periodically review /var/log/fail2ban.log.
  4. Combine with SSH keys: Fail2ban complements, not replaces, public key authentication.
  5. Keep fail2ban updated: Updates include new filters and security fixes.

References