Quick Answer:
apt install fail2ban -y. It works immediately for SSH with default settings — bans IPs for 10 minutes after 5 failed login attempts. Check banned IPs:fail2ban-client status sshd. Unban:fail2ban-client set sshd unbanip 1.2.3.4.
What is Fail2ban?
Fail2ban monitors log files for suspicious activity and automatically bans offending IPs using your firewall. It protects against:
- SSH brute-force attacks
- Web login brute-force
- Bot scanning
- Denial of service attempts
Install
# Ubuntu/Debian
sudo apt update && sudo apt install fail2ban -y
# CentOS/RHEL
sudo yum install epel-release -y && sudo yum install fail2ban -y
# Start and enable
sudo systemctl enable --now fail2ban
# Check status
sudo systemctl status fail2ban
How It Works
- Fail2ban watches log files (e.g.,
/var/log/auth.log) - It matches lines against patterns (filters)
- If an IP triggers too many matches within a time window, it gets banned
- Ban = firewall rule blocking that IP
- After the ban time expires, the IP is automatically unbanned
Configuration
Never edit the default files. Create .local overrides instead:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
sudo nano /etc/fail2ban/jail.local
Global Settings
[DEFAULT]
# Ban duration (seconds). 1h = 3600, 24h = 86400
bantime = 3600
# Time window to count failures
findtime = 600
# Max failures before ban
maxretry = 5
# What to use for banning
banaction = iptables-multiport
# Email notifications (optional)
# destemail = [email protected]
# action = %(action_mwl)s
SSH Jail (Enabled by Default)
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 3600
findtime = 600
This bans an IP for 1 hour after 3 failed SSH attempts within 10 minutes.
Nginx Jails
# Block repeated 401/403 errors (login brute-force)
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
# Block bots scanning for vulnerabilities
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
# Block repeated 404s (scanners)
[nginx-404]
enabled = true
port = http,https
filter = nginx-404
logpath = /var/log/nginx/access.log
maxretry = 10
findtime = 60
bantime = 3600
Create the 404 filter /etc/fail2ban/filter.d/nginx-404.conf:
[Definition]
failregex = ^<HOST> -\s+.*\[.*\]\s+"(GET|POST|HEAD) .* HTTP/.*" 404
ignoreregex =
Aggressive SSH Protection
[sshd-aggressive]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400 # 24 hours
findtime = 3600 # 1 hour window
# Repeat offenders get longer bans
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
maxretry = 3
bantime = 604800 # 1 week
findtime = 86400 # If banned 3 times in 24h
Apply Changes
sudo systemctl restart fail2ban
Managing Bans
# Status overview
sudo fail2ban-client status
# Status of specific jail
sudo fail2ban-client status sshd
# List banned IPs
sudo fail2ban-client status sshd | grep "Banned IP"
# Ban an IP manually
sudo fail2ban-client set sshd banip 1.2.3.4
# Unban an IP
sudo fail2ban-client set sshd unbanip 1.2.3.4
# Check if a specific IP is banned
sudo fail2ban-client get sshd banned | grep 1.2.3.4
# Unban all
sudo fail2ban-client unban --all
Whitelist Your IP
Never lock yourself out — add your IP to the ignore list:
# In jail.local under [DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_HOME_IP
Monitoring
# Watch fail2ban log (live)
sudo tail -f /var/log/fail2ban.log
# Count total bans today
sudo grep "Ban" /var/log/fail2ban.log | grep "$(date +%Y-%m-%d)" | wc -l
# Most banned IPs
sudo grep "Ban" /var/log/fail2ban.log | awk '{print $NF}' | sort | uniq -c | sort -rn | head -10
# Test a filter against a log file
sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf
Troubleshooting
| Problem | Fix |
|---|---|
| Fail2ban not banning | Check fail2ban-regex — filter might not match your log format |
| Banned myself | Use server console to run fail2ban-client set sshd unbanip YOUR_IP |
| Bans not persisting after restart | Normal — fail2ban clears bans on restart. Use bantime = -1 for permanent |
| High CPU usage | Too many jails or too-frequent log scanning. Increase findtime |
| Not starting | Check journalctl -u fail2ban for errors |