Applies to: Fail2Ban 1.1.0 (Debian 13, Ubuntu 26.04, AlmaLinux 10 from EPEL) and Fail2Ban 1.0.2 (Ubuntu 24.04)
Fail2Ban is a free, open-source tool that watches your server's logs for repeated failed logins and blocks the IP addresses behind them with a firewall rule for a set time. Its best-known use is stopping SSH password-guessing bots: after, say, five wrong passwords in ten minutes, the IP cannot reach SSH for an hour. Install it with apt install fail2ban (Debian, Ubuntu) or from EPEL with dnf install fail2ban (AlmaLinux, Rocky Linux), put your settings in /etc/fail2ban/jail.local, and check it with fail2ban-client status sshd.
The Fail2Ban project itself points out that it reduces the rate of password guessing but cannot make weak passwords safe. Use it together with SSH keys, not instead of them.
How Fail2Ban works
- Jail: one protected service, such as
sshd. A jail combines a filter and an action. - Filter: patterns that recognise a failed login in the log. Fail2Ban ships filters for SSH, Apache, Nginx, Postfix, Dovecot, vsftpd and many more in
/etc/fail2ban/filter.d/. - Action: what to do with a banned IP, usually a firewall rule (nftables, iptables, firewalld or UFW).
- maxretry, findtime, bantime: an IP is banned after
maxretryfailures withinfindtime, forbantime. The built-in defaults are 5 failures, 10 minutes and a 10-minute ban. - backend: where Fail2Ban reads from: a log file, or the systemd journal (
backend = systemd).
Step 1: Install Fail2Ban
Ubuntu and Debian:
sudo apt update sudo apt install fail2ban
On Debian 13, Ubuntu 24.04 and Ubuntu 26.04 the package already turns on the SSH jail. Its file /etc/fail2ban/jail.d/defaults-debian.conf enables [sshd], reads SSH failures from the systemd journal and bans with nftables. The package also starts the service and enables it at boot. Check that it runs:
sudo systemctl status fail2ban sudo systemctl enable --now fail2ban # only if it is not running
AlmaLinux and Rocky Linux (from the EPEL repository):
sudo dnf install epel-release sudo dnf install fail2ban sudo systemctl enable --now fail2ban
On AlmaLinux 10 this installed Fail2Ban 1.1.0 together with fail2ban-firewalld and firewalld itself. That package sets banaction = firewallcmd-rich-rules, so bans only work while firewalld is running. Unlike Debian and Ubuntu, no jail is enabled after installing and the service is disabled, so you must do step 2 before it protects anything. If you start firewalld for the first time, open your other ports first: see how to open a port in firewalld.
Step 2: Create jail.local
Do not edit jail.conf: the file itself says it will probably be overwritten in a distribution update. Fail2Ban reads jail.conf, then jail.d/*.conf, then jail.local, then jail.d/*.local, and later files win. Create /etc/fail2ban/jail.local with only the settings you want to change:
[DEFAULT] bantime = 1h findtime = 10m maxretry = 5 # never ban these (your office IP, monitoring) ignoreip = 127.0.0.1/8 ::1 203.0.113.10 [sshd] enabled = true maxretry = 3
- ignoreip takes IP addresses and CIDR ranges, separated by spaces. Add your own fixed IP so a few mistyped passwords cannot lock you out.
- Times are seconds or abbreviations such as
10m,1h,1dand1w. Months aremo, becausemmeans minutes. - Custom SSH port: if SSH listens on another port, add
port = 2222under[sshd]. In our test the nftables rule changed fromtcp dport 22totcp dport 2222. Without it, Fail2Ban bans the wrong port. (Changing the port: the default SSH port and how to change it safely.) - Repeat offenders:
bantime.increment = truemakes each new ban of the same IP longer (by default 1, 2, 4, 8 times the bantime and so on, according to the comments injail.conf). Fail2Ban keeps its bans in a database and restored them after a restart in our test (Restore Ban 203.0.113.77in the log).
Do not add a logpath for SSH on these systems. Debian, Ubuntu and AlmaLinux packages already read SSH failures from the journal.
Step 3: Test the configuration and restart
$ sudo fail2ban-client -t OK: configuration test is successful $ sudo systemctl restart fail2ban
Small changes can also be applied with sudo fail2ban-client reload.
Step 4: Check bans with fail2ban-client
Lab example (test container, four failed root logins from a documentation IP with maxretry = 3):
$ sudo fail2ban-client status Status |- Number of jail: 1 `- Jail list: sshd $ sudo fail2ban-client status sshd Status for the jail: sshd |- Filter | |- Currently failed: 2 | |- Total failed: 6 | `- File list: /var/log/auth.log `- Actions |- Currently banned: 1 |- Total banned: 1 `- Banned IP list: 203.0.113.50
Our lab read a log file because the container has no systemd journal. With the journal backend on a real server, the last filter line is Journal matches instead of File list, according to the Fail2Ban source code. sudo fail2ban-client banned lists bans for all jails at once: [{'sshd': ['203.0.113.50']}].
The ban itself is a firewall rule. On Debian and Ubuntu, Fail2Ban adds its own nftables table:
$ sudo nft list ruleset
table inet f2b-table {
set addr-set-sshd {
type ipv4_addr
elements = { 203.0.113.50 }
}
chain f2b-chain {
type filter hook input priority filter - 1; policy accept;
tcp dport 22 ip saddr @addr-set-sshd reject with icmp port-unreachable
}
}
This table is separate from UFW's rules. If you would rather manage bans as UFW rules, Fail2Ban ships a ufw action: set banaction = ufw in [DEFAULT] and each ban is added with a ufw command. With firewalld (AlmaLinux and Rocky), bans are rich rules: sudo firewall-cmd --list-rich-rules.
Step 5: Unban or ban an IP
$ sudo fail2ban-client set sshd unbanip 203.0.113.50 1 $ sudo fail2ban-client unban 198.51.100.23 1 $ sudo fail2ban-client set sshd banip 198.51.100.23 1
set sshd unbanipremoves the ban from one jail;unbanremoves it from every jail. The1means one IP was unbanned;0means it was not banned.fail2ban-client set sshd addignoreip 198.51.100.0/24whitelists a range at once, but only until the next reload or restart: afterreloadit was gone in our test. Put permanent entries inignoreipinjail.local.- Locked out of your own server? Connect from another network or use the server console (the VPS panel's console, or IPMI on a dedicated server), then unban your IP and add it to
ignoreip.
Common problems
- "Have not found any log file for sshd jail" and Fail2Ban will not start: the jail is told to read
/var/log/auth.log, but the system logs to the journal only (Debian 12 and 13 do not install rsyslog by default). We got this error by settingbackend = autounder[sshd]on Debian 13. Remove that override so the package defaultbackend = systemdapplies, or install rsyslog. - Warning "'allowipv6' not defined in 'Definition'. Using default one: 'auto'" on Ubuntu 24.04 (Fail2Ban 1.0.2): it is only a warning. It disappeared in our test after creating
/etc/fail2ban/fail2ban.localwith the two lines[Definition]andallowipv6 = auto. Fail2Ban 1.1.0 on Debian 13 and Ubuntu 26.04 did not show it. - Nothing gets banned on AlmaLinux: check that the
[sshd]jail is enabled injail.localand that firewalld is running (sudo firewall-cmd --state). - Check a filter against a log:
sudo fail2ban-regex /var/log/auth.log sshdshows how many lines matched (our lab log:Lines: 10 lines, 0 ignored, 10 matched, 0 missed).
Other jails worth knowing
- recidive: reads Fail2Ban's own log and bans IPs that keep getting banned, across all ports (defaults in
jail.conf:findtime = 1d,bantime = 1w). Enable it with[recidive]andenabled = true. - Web and mail: filters such as
nginx-http-auth,apache-auth,postfixanddovecotare included. Enable only the jails for services you really run. - cPanel servers: cPanel has its own protection, cPHulk, which according to cPanel watches SSH, cPanel, WHM, mail and Pure-FTPd logins. Use cPHulk there rather than adding Fail2Ban on top.
Fail2Ban works on any Ucartz KVM VPS or dedicated server with root access. If you would rather have it set up as part of a full hardening job, see Linux server management.
Related articles: how to set up SSH keys for authentication, how to disable root login via SSH, how to set up the UFW firewall on Ubuntu, useful firewall-cmd examples.
Official documentation: Fail2Ban on GitHub, jail.conf(5) manual.