Fail2ban for SSH on Ubuntu: Setup, Tuning, and the Day It Banned Me

Fail2ban watches your auth log, counts failed login attempts per source IP, and bans the source after a configurable threshold. With SSH key authentication and password auth disabled, brute-force attempts can’t succeed anyway — but they still hit your logs, consume CPU, and clutter journalctl. Fail2ban makes them go away.

Prerequisite: SSH already enabled and ideally with key auth and password auth disabled. Fail2ban is a defence-in-depth layer, not a replacement.

Tested on: Ubuntu Server 22.04 LTS, 24.04 LTS. Fail2ban version 0.11.x and 1.0.x.

Install

sudo apt update
sudo apt install fail2ban

The default config enables an SSH jail out of the box — ssh attempts already get monitored on a fresh install. But the defaults are conservative; you’ll want to tune them.

Verify it’s running

sudo systemctl status fail2ban

You want Active: active (running).

To see currently active jails:

sudo fail2ban-client status

You should see sshd in the jail list. To see the SSH jail’s current state:

sudo fail2ban-client status sshd

Output shows currently banned IPs, total bans since start, and the log file being monitored.

Custom configuration

The default config lives in /etc/fail2ban/jail.conf. Don’t edit it directly — changes get overwritten on package updates. Instead create /etc/fail2ban/jail.local with your overrides.

sudo nano /etc/fail2ban/jail.local

Recommended starting point:

[DEFAULT]
# Whitelist your home IP and any trusted networks
ignoreip = 127.0.0.1/8 ::1 192.168.1.0/24

# Ban time in seconds (3600 = 1 hour)
bantime = 3600

# Window for counting failures (600 = 10 minutes)
findtime = 600

# How many failures before ban
maxretry = 3

# Where the ban list is saved (so it survives reboots)
banaction = ufw

[sshd]
enabled = true
port    = ssh
logpath = %(sshd_log)s
backend = systemd

Reload after editing:

sudo systemctl restart fail2ban

What each setting actually does

  • ignoreip: IPs in this list are NEVER banned. Add your home IP, your office IP, your phone’s hotspot range. Your VPN’s egress range if you use one.
  • bantime: how long an IP stays banned. 1 hour for noisy scanners, 24 hours (86400) for repeat offenders. Set to -1 for permanent.
  • findtime: the window during which maxretry failures triggers a ban. 10 minutes is reasonable — long enough to catch slow attempts, short enough that legitimate typos don’t accumulate.
  • maxretry: how many failed auths in findtime triggers a ban. 3 is tight; 5 is more forgiving.
  • banaction = ufw: integrate with ufw so bans become firewall rules. Without this, fail2ban uses iptables directly — works fine but doesn’t show up in ufw status.

Whitelist your own IP (do this first)

Locking yourself out of your own server is the rite of passage. Avoid it:

# What's my current IP?
curl ifconfig.me

# Add to /etc/fail2ban/jail.local under [DEFAULT]
ignoreip = 127.0.0.1/8 ::1 YOUR_IP_HERE

Restart fail2ban. Now you can fail-test from another machine without banning yourself in the process.

For dynamic IPs (most home internet connections), the safer move is to whitelist a Tailscale range or VPN range that you always connect through.

Test it works

From a second IP (NOT your whitelisted one) — a phone on mobile data is fine — intentionally fail SSH a few times:

ssh wrong-username@your-server-ip
# enter wrong password 3 times

Then on the server, check the jail:

sudo fail2ban-client status sshd

You should see the test IP in the banned list. To verify the firewall rule:

sudo ufw status numbered

You should see a deny rule for that IP at the top of the list.

Unban yourself (when you do, eventually, lock yourself out)

If you’ve banned an IP you didn’t mean to:

sudo fail2ban-client unban 192.168.1.50
# or unban everything currently banned
sudo fail2ban-client unban --all

Or remove from the firewall directly:

sudo ufw delete deny from 192.168.1.50

If you’re locked out of the server entirely (banned your own home IP from outside) — you need physical access or out-of-band console (KVM, hosting provider’s console). Edit /etc/fail2ban/jail.local, add your IP to ignoreip, restart fail2ban, unban yourself.

This is why mesh VPNs are useful. If your SSH access is via Tailscale, locking yourself out of internet-facing SSH doesn’t matter — you still have Tailscale.

Custom log message hooks

If you want to know when bans happen, add an action that emails you (or pushes to Telegram, Slack, whatever). Out-of-the-box, fail2ban supports email via the mta action.

[sshd]
enabled = true
action = %(action_mwl)s
sender = [email protected]
destemail = [email protected]
mta = sendmail

action_mwl = mail with whois log — emails you the banned IP, geolocation, and the relevant log lines.

For Telegram or Slack, you’ll need a custom action. Not built into the package — search “fail2ban telegram action” for community-maintained scripts.

Troubleshooting

“Failed to access socket path: /var/run/fail2ban/fail2ban.sock”

Fail2ban isn’t running. sudo systemctl start fail2ban and check journalctl -u fail2ban for the actual error.

Bans aren’t happening

Check the jail backend. On Ubuntu 22.04+, systemd-journald is the log source, not /var/log/auth.log. Make sure backend = systemd is set.

IPs are banned but still connecting

The banaction is firing but the firewall rule isn’t being applied. Check sudo ufw status for the deny rule. If banaction = ufw but ufw isn’t enabled, the ban is a no-op. Run sudo ufw enable (after allowing SSH first if remote).

My phone got banned during a normal session

Mobile carriers sometimes route through different exit IPs mid-session, which can look like multiple failed sessions from different IPs. Increase findtime and maxretry if this happens often, or whitelist the carrier’s range.

Trust, but tune

The defaults err on the side of “block scanners aggressively.” For a homelab where you control the clients, that’s perfect. For a customer-facing server where legitimate users sometimes typo their password, you may want to raise maxretry to 5 and lower bantime to 600 seconds.

Watch the logs for a week after install:

sudo journalctl -u fail2ban -n 100

If you’re banning IPs that turn out to be your own users, tune. If the only bans are obvious scanners, leave the config tight.

What this doesn’t replace

  • Disabling password auth entirely (see SSH Hardening). Far stronger than relying on fail2ban catching brute-forces.
  • Restricting SSH to specific source IPs at the firewall. Even better.
  • Putting SSH behind a VPN (Tailscale, NetBird, WireGuard). Best.

Fail2ban is the cheap insurance layer that comes after the structural fixes.

From Pi-hole Logs to Enterprise Threat Detection

Fail2ban on your homelab teaches you the same intrusion detection principles as CrowdSec, OSSEC, or the alerting rules in an enterprise SIEM. Watch logs, detect patterns, take automated action. The brute-force attempts hitting your Pi on port 22 are the same ones hitting corporate infrastructure, from the same botnets, using the same credential lists.

Understanding how fail2ban parses auth logs, applies regex filters, and triggers firewall rules gives you a practical grasp of detection engineering that transfers directly to tools like Wazuh or Splunk. The scale is different. The thinking is identical.


Companion guides: Enable SSH on Ubuntu Server, SSH Hardening, SSH Key Authentication on Ubuntu.

Enjoyed this guide?

New articles on Linux, homelab, cloud, and automation every 2 days. No spam, unsubscribe anytime.

Scroll to Top