Fail2ban watches log files for repeated failures — wrong SSH passwords, failed WordPress logins, mail auth errors — and adds a firewall rule that drops the offending IP for a while. It turns tens of thousands of daily attempts into a handful, and it is a ten-minute install.
Install
# Ubuntu / Debian
sudo apt install fail2ban -y
# AlmaLinux / Rocky (EPEL provides it)
sudo dnf install epel-release -y && sudo dnf install fail2ban -y
sudo systemctl enable --now fail2banPlesk ships its own Fail2ban integration under Tools & Settings → IP Address Banning (Fail2Ban); if you are on Plesk, turn it on there and the jails below are pre-configured with a switch each.
How it works
Three words cover the configuration:
- Jail — one thing to watch: a log file plus a pattern that means "failure" plus an action.
- maxretry — how many failures within findtime trigger a ban.
- bantime — how long the ban lasts.
Never edit jail.conf; it is overwritten on updates. Put your settings in jail.local:
sudo nano /etc/fail2ban/jail.local[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 203.0.113.50
backend = systemd
[sshd]
enabled = trueignoreip is your own address — the one thing you must set, or a mistyped password locks you out of your own server for an hour. Find it with curl -s ifconfig.me from your machine.
sudo systemctl restart fail2ban
sudo fail2ban-client status sshdEscalate repeat offenders
The default ban is short so a legitimate user's typo is not a disaster. Add a "recidive" jail that watches Fail2ban's own log and bans for a week anyone who has been banned several times:
[recidive]
enabled = true
bantime = 1w
findtime = 1d
maxretry = 3Protect Nginx and the web login pages
Plain HTTP brute force hits WordPress wp-login.php and xmlrpc.php. Create a filter:
sudo nano /etc/fail2ban/filter.d/wordpress-login.conf[Definition]
failregex = ^<HOST> .* "POST /(wp-login\.php|xmlrpc\.php)
ignoreregex =And a jail using the access log:
[wordpress-login]
enabled = true
port = http,https
filter = wordpress-login
logpath = /var/www/vhosts/*/logs/access_ssl_log
/var/log/nginx/access.log
maxretry = 8
findtime = 5m
bantime = 2hEight POSTs to the login page in five minutes is not a person. Legitimate users who mistype twice are unaffected.
For Nginx's own auth and bad-bot patterns, the shipped nginx-http-auth and nginx-botsearch jails just need enabled = true.
Mail servers
Fail2ban ships jails for Postfix and Dovecot (postfix, postfix-sasl, dovecot). Enable them on any server that receives mail; SMTP auth is attacked as hard as SSH.
See what it is doing
sudo fail2ban-client status # list of jails
sudo fail2ban-client status sshd # banned IPs in one jail
sudo tail -f /var/log/fail2ban.log # bans and unbans liveUnban an address (yours, usually):
sudo fail2ban-client set sshd unbanip 203.0.113.50A summary of who is being banned and from where is a useful monthly read:
sudo zgrep "Ban " /var/log/fail2ban.log* | awk '{print $NF}' | sort | uniq -c | sort -rn | headWhat Fail2ban does not do
It reacts after failures are logged, so it does not stop a distributed attack that uses a different IP per attempt, and it cannot see failures that never reach a log. For SSH, the real fix is keys with passwords disabled — Fail2ban then just keeps the log quiet. For WordPress, pair it with two-factor authentication. For volume attacks, see DDoS and how Anti-DDoS works.
On VPSPioneer shared plans Fail2ban runs on every server with the SSH, mail, Plesk and WordPress jails enabled; on a managed VPS it is part of the hardening we do before handover.