Skip to main content
Back to Category

Fail2Ban Configuration: SSH Brute-Force Protection Guide

Protect your server against SSH brute-force attacks with Fail2Ban. Installation, jail.local configuration, Nginx/Apache jails, IP whitelisting, ban monitoring, and email alerts.

Read time: 13 min Security
fail2banbrute-forcessh securitysecuritylinuxiptablesnginxapache

Table of Contents

Fail2Ban Configuration: SSH Brute-Force Protection Guide

SSH brute-force attacks are among the most common threats faced by every internet-facing server. Fail2Ban is a powerful tool that monitors failed login attempts and automatically blocks attacker IP addresses. This guide walks you through setting up Fail2Ban with comprehensive protection for SSH, Nginx, and Apache.

What is Fail2Ban?

Fail2Ban is a security tool that monitors log files and blocks IP addresses that make too many failed login attempts within a given time window using iptables/nftables rules. Written in Python, it includes ready-made filters for many services.

Installation

hljs bash
# Ubuntu/Debian
sudo apt update
sudo apt install fail2ban -y

# CentOS/AlmaLinux/Rocky Linux
sudo dnf install epel-release -y
sudo dnf install fail2ban -y

# Start Fail2Ban service
sudo systemctl start fail2ban
sudo systemctl enable fail2ban

# Check status
sudo systemctl status fail2ban

jail.local Configuration

Fail2Ban's main configuration file is jail.conf. However, don't edit this file directly — it may be overwritten during updates. Instead, create a jail.local file:

hljs bash
# Copy jail.conf
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

# Edit configuration
sudo nano /etc/fail2ban/jail.local
hljs ini
# /etc/fail2ban/jail.local

[DEFAULT]
# Ban duration (seconds) — 1 hour
bantime = 3600

# Detection window (seconds) — 10 minutes
findtime = 600

# Maximum failed attempts
maxretry = 5

# Backend (auto, pyinotify, gamin, polling, systemd)
backend = auto

# DNS resolution (warn, no, yes)
usedns = warn

# Log level (CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG)
loglevel = INFO

# Log target
logtarget = /var/log/fail2ban.log

# Email notification
destemail = admin@example.com
sender = fail2ban@example.com
mta = sendmail

# Action — ban and send email
action = %(action_mwl)s
# Ban only (no email):
# action = %(action_)s

# Whitelist — these IPs are never banned
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

SSH Jail Configuration

hljs ini
# Inside /etc/fail2ban/jail.local

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
# For Ubuntu 20.04+:
# logpath = %(sshd_log)s
maxretry = 3
bantime = 86400  # 24 hours
findtime = 600

# If using systemd journal:
# backend = systemd

For SSH, maxretry = 3 and bantime = 86400 (24 hours) are recommended. This allows attackers only 3 attempts per day.

Nginx Jail Configuration

hljs ini
# Nginx HTTP authentication failure
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
bantime = 3600

# Nginx rate limiting violation
[nginx-limit-req]
enabled = true
port = http,https
filter = nginx-limit-req
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 600

# Nginx bad bot blocking
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400

# Nginx 404 flood protection
[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/access.log
maxretry = 20
findtime = 60
bantime = 3600

Creating a Custom Nginx 404 Filter

hljs bash
sudo nano /etc/fail2ban/filter.d/nginx-404.conf
hljs ini
[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD) .* HTTP/.*" 404
ignoreregex =

Apache Jail Configuration

hljs ini
# Apache authentication failure
[apache-auth]
enabled = true
port = http,https
filter = apache-auth
logpath = /var/log/apache2/error.log
maxretry = 5
bantime = 3600

# Apache bad bots
[apache-badbots]
enabled = true
port = http,https
filter = apache-badbots
logpath = /var/log/apache2/access.log
maxretry = 2
bantime = 86400

# Apache nuke/scan
[apache-noscript]
enabled = true
port = http,https
filter = apache-noscript
logpath = /var/log/apache2/error.log
maxretry = 6
bantime = 3600

IP Whitelisting

hljs bash
# Add to DEFAULT section in jail.local
sudo nano /etc/fail2ban/jail.local
hljs ini
[DEFAULT]
# You can add multiple IPs or subnets
ignoreip = 127.0.0.1/8 ::1 10.0.0.0/8 192.168.0.0/16 203.0.113.1
hljs bash
# Reload configuration
sudo fail2ban-client reload

# Verify whitelist
sudo fail2ban-client get sshd ignoreip

Monitoring Banned IPs

hljs bash
# View status of all jails
sudo fail2ban-client status

# View status of a specific jail
sudo fail2ban-client status sshd

# List banned IPs
sudo fail2ban-client status sshd | grep "Banned IP"

# Show all banned IPs
sudo iptables -L f2b-sshd -n --line-numbers

# Monitor log file
sudo tail -f /var/log/fail2ban.log

# Filter recent ban events
sudo grep "Ban" /var/log/fail2ban.log | tail -20

Banning and Unbanning IPs

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

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

# Remove all bans (use with caution!)
sudo fail2ban-client unban --all

# Restart a specific jail
sudo fail2ban-client restart sshd

Email Notifications

hljs bash
# Install Postfix or sendmail
sudo apt install postfix -y
hljs ini
[DEFAULT]
destemail = admin@example.com
sender = fail2ban@yourdomain.com
mta = sendmail

# Action options:
# action_ = ban only
# action_mw = ban + email
# action_mwl = ban + email + whois + log lines
action = %(action_mwl)s

Checking Fail2Ban Status

hljs bash
# Service status
sudo systemctl status fail2ban

# Test configuration
sudo fail2ban-client -t

# List all jails
sudo fail2ban-client status

# Restart Fail2Ban
sudo systemctl restart fail2ban

# Reload configuration (without restarting service)
sudo fail2ban-client reload

Advanced: Persistent Banning

By default, Fail2Ban resets bans when the server restarts. For persistent banning:

hljs ini
[DEFAULT]
# Permanent ban (-1 = forever)
bantime = -1

# Or very long duration:
bantime = 604800  # 7 days

Very aggressive settings (low maxretry, long bantime) can also block legitimate users. For SSH, maxretry=3-5 and bantime=3600-86400 is a balanced approach.

Conclusion

Fail2Ban is an indispensable part of server security. When properly configured for SSH, Nginx, and Apache, it significantly reduces brute-force attacks. Regularly monitor log files and whitelist any false-positive blocks.