Fail2ban watches your logs and bans IP addresses that fail to log in too often. The defaults work, but they are mild: a ten-minute ban barely slows a botnet. This guide shows how to set your own values in jail.local, make repeat offenders wait longer each time, and keep your own IP address safe from bans.
Before you start
- A Linux VPS running Ubuntu 22.04 or 24.04, Debian 12, or AlmaLinux or Rocky Linux 8 or 9.
- A user with
sudo. - Fail2ban installed and running. If it is not, follow Install Fail2ban to block brute-force attacks first.
- Your own public IP address. Run
curl -4 ifconfig.mefrom your home computer, not the server, or check a "what is my IP" site.
Why you edit jail.local, not jail.conf
Fail2ban reads its settings in layers:
/etc/fail2ban/jail.confholds the shipped defaults. Package updates overwrite it.- Files in
/etc/fail2ban/jail.d/(ending in.conf, then.local) are read next. /etc/fail2ban/jail.localis read last and wins.
So never edit jail.conf. Put only the settings you want to change into jail.local. Do not copy the whole jail.conf across either: that freezes old defaults and makes upgrades harder to follow.
Also check what your distribution already sets in jail.d:
ls /etc/fail2ban/jail.d/
grep -rv '^#' /etc/fail2ban/jail.d/ | grep -v ':$'Debian and Ubuntu ship defaults-debian.conf, which enables the sshd jail. On AlmaLinux and Rocky the fail2ban-firewalld package adds 00-firewalld.conf, which sets the firewalld ban action.
What bantime, findtime and maxretry do
Three settings decide when an IP is banned and for how long:
- maxretry: how many failures are allowed.
- findtime: the time window those failures must happen in.
- bantime: how long the ban lasts.
With maxretry = 5 and findtime = 10m, an address is banned on its fifth failure within any ten-minute window. Fail2ban accepts time units such as 30s, 10m, 1h, 1d and 1w. A bantime of -1 means a permanent ban, which is rarely a good idea because addresses change hands.
Write a jail.local
Create the file:
sudo nano /etc/fail2ban/jail.localA sensible starting point:
[DEFAULT]
; Never ban yourself. Add your home/office IP or range.
ignoreip = 127.0.0.1/8 ::1 203.0.113.10
; Base ban: 1 hour after 5 failures in 10 minutes
bantime = 1h
findtime = 10m
maxretry = 5
; Repeat offenders wait longer each time
bantime.increment = true
bantime.factor = 2
bantime.maxtime = 1w
[sshd]
enabled = true
port = ssh
backend = systemdReplace 203.0.113.10 with your real IP address. You can list several addresses and CIDR ranges, separated by spaces.
Warning: Always put your own IP in ignoreip before you tighten the limits. One mistyped password too many and you are banned from SSH. If that happens, log in through the browser console in the control panel of your VPS provider's control panel, which does not go through the network firewall, then unban yourself.
Incremental bans
With bantime.increment = true, each new ban for the same IP is longer than the last. Using the values above, the first ban is one hour, the next is longer, and growth stops at bantime.maxtime (one week here). Fail2ban remembers past bans in its database, /var/lib/fail2ban/fail2ban.sqlite3, so this works across restarts. Incremental bans need Fail2ban 0.11 or newer; check your version with fail2ban-client version.
Custom SSH port
If you moved SSH to another port, tell the jail. Otherwise Fail2ban bans the address on port 22 only, and the attacker keeps hammering your real port:
[sshd]
enabled = true
port = 2222
backend = systemdSee Change the SSH port safely for the rest of that change.
Pick the right log backend
Fail2ban needs to read the log where SSH failures are written.
- Debian 12 does not install rsyslog by default, so
/var/log/auth.logdoes not exist. Usebackend = systemdso Fail2ban reads the journal. Without it, thesshdjail can fail to start. - Ubuntu 22.04 and 24.04 write
/var/log/auth.log, but the journal works too.backend = systemdis a safe choice on both. - AlmaLinux and Rocky log SSH to
/var/log/secureand the journal.backend = systemdworks here as well.
The systemd backend needs the Python systemd bindings. On Debian and Ubuntu that is python3-systemd:
sudo apt install python3-systemdOn AlmaLinux and Rocky, the EPEL fail2ban packages pull in what they need.
Reload and test
Check the configuration for errors first. -t tests without changing anything:
sudo fail2ban-client -tThen reload:
sudo fail2ban-client reloadIf the test reports an error, fix jail.local before you reload. A broken config can stop every jail.
Check it works
List the active jails:
sudo fail2ban-client statusThen look at the SSH jail:
sudo fail2ban-client status sshdYou should see Currently failed and Total banned counters. On a public server they usually start rising within minutes. To confirm your values loaded, ask Fail2ban directly:
sudo fail2ban-client get sshd bantime
sudo fail2ban-client get sshd maxretry
sudo fail2ban-client get sshd ignoreipTo test a real ban without risking your own access, try a few wrong passwords from a different network, such as a phone hotspot, and watch that address appear in the banned list.
Troubleshooting
sshdjail does not start on Debian 12: there is no/var/log/auth.log. Setbackend = systemdand installpython3-systemd.- Your changes have no effect: you edited
jail.conf, or a file injail.dsets the same option later than you expect. Put overrides injail.localand confirm withfail2ban-client get. bantime.incrementis ignored: your Fail2ban is older than 0.11. Upgrade or use a single fixedbantime.- You banned yourself: log in through your VPS provider's browser console and run
sudo fail2ban-client set sshd unbanip YOUR_IP. Then add your IP toignoreip. - Attackers keep trying after a ban: the jail's
portdoes not match your real SSH port. Fixportand reload.
Next steps
- Learn to read and lift bans: Check banned IPs and unban an address in Fail2ban.
- Protect your web server too: Protect Nginx with Fail2ban.
- Bans not appearing? Work through Fail2ban not banning? Common causes and fixes.
