How to Install and Use Fail2ban on Ubuntu VPS to Block Attacks

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.

Related articles:

Fast • Reliable • Affordable VPS - DO It Now!

Get top VPS hosting with VPS.DO’s fast, low-cost plans. Try risk-free with our 7-day no-questions-asked refund and start today!