How to Install and Use Fail2ban on Ubuntu VPS to Block Attacks
Within minutes of a new VPS going online, automated bots begin scanning it — probing SSH, trying common passwords, looking for open web interfaces. Without protection, these attacks continue 24/7. Fail2ban is the standard Linux tool that fights back automatically: it monitors your log files and permanently bans IP addresses that show malicious behavior.
This guide covers installing Fail2ban, configuring it for SSH and Nginx protection, creating custom jails, and monitoring ban activity on your Ubuntu VPS.
How Fail2ban Works
Fail2ban reads log files in real time, applying regular expression filters to detect failed authentication attempts and other attack patterns. When an IP address triggers a defined threshold (e.g., 5 failed SSH logins in 10 minutes), Fail2ban adds a firewall rule banning that IP for a configured duration — automatically, without human intervention.
| Component | Purpose |
|---|---|
| Filter | Regex pattern that matches attack signatures in log files |
| Jail | Configuration combining a filter + log file + ban parameters |
| Action | What happens when threshold is hit (typically iptables ban) |
| Backend | How Fail2ban monitors log files (systemd recommended on Ubuntu) |
Step 1: Install Fail2ban
sudo apt update
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
Step 2: Create a Local Configuration File
Never edit /etc/fail2ban/jail.conf directly — it gets overwritten on updates. Use a local override file instead:
sudo nano /etc/fail2ban/jail.local
Step 3: Configure Core Jails
[DEFAULT]
# Global settings applied to all jails
ignoreip = 127.0.0.1/8 ::1 YOUR_HOME_IP
bantime = 3600 # Ban for 1 hour (use -1 for permanent)
findtime = 600 # Within a 10-minute window
maxretry = 5 # After 5 failures
backend = systemd # Best for Ubuntu 22.04+
banaction = iptables-multiport
# Email alerts (optional — requires mailutils)
# destemail = you@example.com
# sendername = Fail2ban-VPS
# action = %(action_mwl)s
# ─────────────────────────────────────────
# SSH Protection
# ─────────────────────────────────────────
[sshd]
enabled = true
port = 2222 # Your custom SSH port
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
bantime = 86400 # 24-hour ban for SSH failures
# ─────────────────────────────────────────
# Nginx — Block auth brute force
# ─────────────────────────────────────────
[nginx-http-auth]
enabled = true
port = http,https
filter = nginx-http-auth
logpath = /var/log/nginx/error.log
maxretry = 5
# ─────────────────────────────────────────
# Nginx — Block aggressive bot scanning
# ─────────────────────────────────────────
[nginx-botsearch]
enabled = true
port = http,https
filter = nginx-botsearch
logpath = /var/log/nginx/access.log
maxretry = 2
bantime = 86400
# ─────────────────────────────────────────
# WordPress login protection
# ─────────────────────────────────────────
[wordpress]
enabled = true
port = http,https
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
Step 4: Create a WordPress Login Filter
Fail2ban doesn’t include a WordPress filter by default. Create one:
sudo nano /etc/fail2ban/filter.d/wordpress.conf
[Definition]
# Match failed WordPress login attempts in Nginx access log
failregex = ^ .* "POST /(wp-login\.php|wp-admin/admin-ajax\.php) HTTP.*" (200|400|403|429) .*$
ignoreregex =
Step 5: Create an Nginx Rate-Limit Filter
sudo nano /etc/fail2ban/filter.d/nginx-req-limit.conf
[Definition]
# Ban IPs hitting Nginx rate limit (429 responses)
failregex = limiting requests, excess:.* by zone.*, client:
ignoreregex =
Add the jail to jail.local:
[nginx-req-limit]
enabled = true
port = http,https
filter = nginx-req-limit
logpath = /var/log/nginx/error.log
maxretry = 10
bantime = 3600
Step 6: Restart and Verify
sudo systemctl restart fail2ban
# Check all active jails
sudo fail2ban-client status
# Check a specific jail
sudo fail2ban-client status sshd
sudo fail2ban-client status wordpress
You should see each jail listed as active with its current ban/fail counts.
Managing Bans
View currently banned IPs
sudo fail2ban-client status sshd | grep "Banned IP"
# Or view iptables directly
sudo iptables -L -n | grep -i drop
Manually ban an IP
sudo fail2ban-client set sshd banip 192.168.1.100
Unban an IP (if you accidentally banned yourself)
sudo fail2ban-client set sshd unbanip YOUR_IP
Check the Fail2ban log for ban events
sudo tail -f /var/log/fail2ban.log
Output will show lines like:
2025-01-15 03:47:21 INFO [sshd] Ban 45.83.91.14
2025-01-15 03:52:21 INFO [sshd] Unban 45.83.91.14
Advanced: Permanent Bans for Repeat Offenders
For IPs that are repeatedly banned and unbanned, implement a recidive (repeat offender) jail that applies a much longer ban:
[recidive]
enabled = true
filter = recidive
logpath = /var/log/fail2ban.log
action = iptables-allports[name=recidive]
bantime = 604800 # 1 week
findtime = 86400 # Within 24 hours
maxretry = 3 # After being banned 3 times
Any IP that gets banned in any jail 3 times within 24 hours gets a 1-week block from all ports.
Advanced: GeoIP-Based Blocking
If your server has no legitimate users from certain countries, you can block entire countries using iptables GeoIP modules alongside Fail2ban. This is particularly useful for stopping SSH brute-force campaigns that predominantly originate from specific regions.
sudo apt install xtables-addons-common libtext-csv-xs-perl -y
Detailed GeoIP configuration is covered in the xtables-geoip documentation, but the key benefit is reducing attack traffic before it even reaches Fail2ban’s threshold-based detection.
Monitoring Fail2ban Effectiveness
Daily ban statistics
# Count total bans across all jails
sudo fail2ban-client status | grep "Jail list" | tr ',' '\n' | \
while read jail; do
jail=$(echo $jail | tr -d ' ')
count=$(sudo fail2ban-client status $jail 2>/dev/null | grep "Total banned" | awk '{print $NF}')
echo "$jail: $count total bans"
done
View top attacking IPs in auth.log
grep "Failed password" /var/log/auth.log | \
awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20
Fail2ban + UFW Integration
If you use UFW (recommended), configure Fail2ban to use UFW as its ban action for cleaner firewall management:
sudo nano /etc/fail2ban/jail.local
[DEFAULT]
banaction = ufw
Bans will now appear in UFW’s ruleset, visible with sudo ufw status.
Final Thoughts
Fail2ban is one of the most effective and lowest-maintenance security tools available for a Linux VPS. Once configured, it silently monitors your logs, automatically bans attackers, and protects your SSH, web server, and applications around the clock — with zero ongoing effort required.
Combine Fail2ban with SSH key authentication, a properly configured UFW firewall, and automatic security updates, and your VPS has a robust defense-in-depth security posture against the vast majority of real-world attacks.
- 🇺🇸 USA VPS Plans — from $20/month
- 📋 VPS Security Hardening Checklist: 10 Steps to Protect Your Server
Related articles: