Install Fail2Ban to Block SSH Brute Force Attacks on Ubuntu VPS

Any VPS with a public IP faces SSH brute force attacks around the clock. Bots from around the world scan for Port 22 and try millions of username/password combinations every day. Even with a strong password, these attempts waste CPU resources and flood your auth.log with noise, making it hard to spot real incidents.

Fail2Ban is designed to solve this problem directly. It monitors your log files in real time and automatically bans IPs that exceed your login failure threshold. This guide walks you through the complete setup on Ubuntu 22.04.

Prerequisites: An Ubuntu 20.04/22.04 VPS with root or sudo access, reachable via SSH.

What Is an SSH Brute Force Attack?

A brute force attack means trying every possible username/password combination: root/123456, admin/password, or credentials leaked from previous data breaches. Even if your password is uncrackable, the constant flood of requests consumes server resources and pollutes your logs.

How Fail2Ban Works

Fail2Ban is an Intrusion Prevention Framework written in Python. It operates in three stages:

  1. Monitor: Reads log files such as /var/log/auth.log in real time.
  2. Detect: Matches lines against filter patterns (e.g., "Failed password for root from 1.2.3.4").
  3. Act: Adds an iptables or nftables rule to block that IP temporarily.

Once an IP is banned, all traffic from that source is dropped at the firewall. Fail2Ban automatically unbans the IP after the configured ban duration (default: 10 minutes).

Step 1 — Update System and Install Fail2Ban

sudo apt update && sudo apt upgrade -y
sudo apt install fail2ban -y

Verify the installation and confirm it is running:

sudo systemctl status fail2ban

If you see Active: active (running), Fail2Ban is already protecting your server with default settings.

Enable autostart on reboot:

sudo systemctl enable fail2ban

Step 2 — Understand the Config Structure

Fail2Ban uses two key config files:

Best Practice: Always edit jail.local only. Leave jail.conf untouched so your config survives package updates.

Step 3 — Create and Configure jail.local

Create the file:

sudo nano /etc/fail2ban/jail.local

Paste the following config and adjust the values to your needs:

[DEFAULT]
# Ban an IP that fails login 5 times within 10 minutes
bantime  = 3600          # Ban duration: 1 hour (seconds)
findtime = 600           # Detection window: 10 minutes
maxretry = 5             # Failures allowed before ban

# IPs to never ban (your own machine)
ignoreip = 127.0.0.1/8 ::1

[sshd]
enabled  = true
port     = ssh
filter   = sshd
logpath  = /var/log/auth.log
maxretry = 3             # Stricter for SSH — 3 strikes and you're banned
bantime  = 7200          # Ban for 2 hours

⚠️ Important: If you changed your SSH port, specify it explicitly, e.g. port = 2222 instead of port = ssh. Otherwise Fail2Ban won't monitor the port you're actually using.

Save the file with Ctrl+O and exit with Ctrl+X, then restart Fail2Ban:

sudo systemctl restart fail2ban

Step 4 — Check Status and Active Jails

View a summary of all Fail2Ban jails:

sudo fail2ban-client status

View details for the SSH jail specifically:

sudo fail2ban-client status sshd

The output shows the number of currently banned IPs and the total IPs ever banned.

Step 5 — Unban an IP

If a legitimate user gets accidentally banned, unban them immediately:

sudo fail2ban-client set sshd unbanip 1.2.3.4

Replace 1.2.3.4 with the actual IP address.

Prevention tip: Add your own IP to the ignoreip line in jail.local so you can never accidentally lock yourself out.

Step 6 — Monitor the Log

Fail2Ban logs every ban and unban action to:

sudo tail -f /var/log/fail2ban.log

Example log output showing bans being applied:

2026-05-11 14:32:01,782 fail2ban.actions [12345]: NOTICE  [sshd] Ban 185.22.xxx.xxx
2026-05-11 14:32:01,783 fail2ban.actions [12345]: NOTICE  [sshd] Ban 91.108.xxx.xxx

Confirm Fail2Ban is picking up actual brute force attempts:

sudo grep "Failed password" /var/log/auth.log | tail -20

Bonus: Recidive Jail — Long-Term Bans for Repeat Offenders

The Recidive jail bans IPs for a full week if they keep getting banned repeatedly. Add this to jail.local:

[recidive]
enabled  = true
logpath  = /var/log/fail2ban.log
banaction = %(banaction_allports)s
bantime  = 604800   # 1 week
findtime = 86400    # Look back 1 day
maxretry = 3        # Banned 3 times in 1 day → 1-week ban

Add Jails for Nginx, Apache, and WordPress

Fail2Ban protects far more than SSH. If your VPS runs a web server like Nginx or Apache, you can add jails to block IPs that launch Layer 7 attacks: brute force against the WordPress login, rapid 404 probing to scan for vulnerabilities, or bad bots that scrape aggressively and waste bandwidth.

Nginx Jail (HTTP Auth + Bad Bot)

Add the following to /etc/fail2ban/jail.local for VPS servers running Nginx:

[nginx-http-auth]
enabled  = true
filter   = nginx-http-auth
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 5
bantime  = 3600

[nginx-botsearch]
enabled  = true
filter   = nginx-botsearch
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 10
findtime = 600
bantime  = 7200      # Block bots scanning for vulnerable paths

Apache Jail

If your VPS uses Apache (for example, with DirectAdmin), use the apache-* filter family instead:

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

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

WordPress Jail (wp-login.php / xmlrpc.php)

WordPress is a top brute force target via wp-login.php and xmlrpc.php. Fail2Ban has no built-in WordPress filter, so create one at /etc/fail2ban/filter.d/wordpress.conf:

[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
            ^<HOST> .* "POST /xmlrpc.php
ignoreregex =

Then add a jail referencing this filter in jail.local (set logpath to match your domain's access log):

[wordpress]
enabled  = true
filter   = wordpress
port     = http,https
logpath  = /var/log/nginx/access.log
maxretry = 5
findtime = 300
bantime  = 7200

⚠️ Watch out: If your site sits behind Cloudflare or a reverse proxy, the IP in the log will be the proxy's, not the real visitor's. Configure Nginx/Apache to log X-Forwarded-For first, otherwise Fail2Ban will ban Cloudflare's IPs instead of the attacker.

After adding any new jail, always reload and confirm the filter has no syntax errors:

sudo fail2ban-client reload
sudo fail2ban-client status

Inspect and Manage Bans with fail2ban-client

Once you have several jails running, you need the fail2ban-client commands to get an overview and manage banned IPs. Here are the essentials.

List all active jails:

sudo fail2ban-client status

View details of a specific jail, including the IPs currently banned:

sudo fail2ban-client status wordpress

The table below summarizes the management commands you'll use most:

Command What it does
fail2ban-client status List all running jails
fail2ban-client status sshd Show banned IPs in the sshd jail
fail2ban-client set sshd unbanip IP Unban the specified IP
fail2ban-client set sshd banip IP Manually ban an IP immediately
fail2ban-client reload Reload config without stopping the service

To quickly count the total number of bans applied, grep the log files:

sudo zgrep "Ban" /var/log/fail2ban.log* | wc -l

This command includes compressed (.gz) rotated logs, giving you the full picture of how many attacks have been blocked since you started.

Whitelisting IPs and Common Problems

The headache that haunts every admin is "banning yourself" and getting locked out. Setting a correct whitelist (ignoreip) is just as important as the ban rules. Add your home/office IP and any trusted internal ranges to jail.local:

[DEFAULT]
# Separate each IP/range with a space — supports IPv4 and IPv6
ignoreip = 127.0.0.1/8 ::1 203.0.113.45 198.51.100.0/24

After editing ignoreip, always run sudo systemctl restart fail2ban for the change to take effect. The table below lists common problems and their fixes:

Symptom Cause / Fix
Fail2Ban never bans any IP logpath points to the wrong file, or SSH uses a port not declared in the jail
Suddenly can't SSH in You banned yourself — use your provider's console, then unbanip and add ignoreip
Banning Cloudflare IPs Logs record the proxy IP — configure real_ip / X-Forwarded-For in the web server
Newer Ubuntu has no auth.log Some Ubuntu releases use journald — set backend = systemd in the jail

Lock-out prevention tip: If you use a dynamic home IP that changes often, set up SSH key authentication and disable password login entirely. It is far more secure and removes the worry of SSH brute force altogether.

Setup Checklist

  1. Install Fail2Ban and enable autostart.
  2. Create /etc/fail2ban/jail.local — never edit jail.conf.
  3. Configure [sshd] jail with the correct port number.
  4. Add your own IP to ignoreip to avoid locking yourself out.
  5. Verify with fail2ban-client status sshd.
  6. Optionally enable the Recidive jail for persistent attackers.

Frequently Asked Questions About Fail2Ban

How is Fail2Ban different from a firewall (UFW/iptables)?

A firewall like UFW or iptables sets static rules for which ports are open or closed. Fail2Ban is a dynamic system that reads logs and instructs the firewall to block IPs showing attack behavior, then unbans them when the timer expires. They work together — Fail2Ban adds temporary iptables/nftables rules for you. You don't choose one over the other; you should run both.

Does Fail2Ban use a lot of VPS resources?

Very little. Fail2Ban is a Python daemon that tails log files, using roughly 20-40 MB of RAM with negligible CPU impact on a typical VPS. Even AsiaGB's entry-level VPS from 500 THB/month runs it comfortably without affecting your sites or apps — unless you set a very wide findtime over multi-gigabyte logs, which is uncommon.

If I change my SSH port, do I still need Fail2Ban?

You still should. Changing the port greatly reduces bots that scan Port 22 directly, but it doesn't stop bots that scan all ports or target you specifically. Fail2Ban still catches and bans IPs that find your port — just remember to update port = ssh in the jail to your new port, or Fail2Ban will monitor the wrong one.

Are banned IPs unbanned automatically or do I do it manually?

They are unbanned automatically once the configured bantime elapses — for example, 7200 seconds blocks the IP for 2 hours, then releases it. You can unban early with fail2ban-client set [jail] unbanip [IP], and setting bantime = -1 creates a permanent ban that lasts until you remove it manually.

VPS with Full Root Access for Maximum Security Control

Configure every security setting yourself. Linux VPS starting at 500 THB/month — Thailand or Singapore.

View VPS Plans