Independent hosting operator since 2014 · New York · Dallas · Amsterdam Status Looking Glass Contact
D4 NetworksD4 Networks
Client area Deploy a server
Home / Resources / Set up fail2ban properly on your VPS

Tutorials

Set up fail2ban properly on your VPS

Jul 23, 2026 · 10 min read

fail2ban reads log files for failed logins and blocks the source address in your firewall. On many fresh installs it bans nothing at all, because the sshd jail is watching a log file the system no longer writes.

1. Install it

Ubuntu and Debian use apt and ufw. AlmaLinux, Rocky, and other RHEL-based distros use dnf and firewalld.

Ubuntu and Debian
$ sudo apt update && sudo apt install -y fail2ban
RHEL-based
$ sudo dnf install -y epel-release
$ sudo dnf install -y fail2ban fail2ban-firewalld

fail2ban is not in the AlmaLinux, Rocky, or RHEL base repositories, so EPEL comes first. The fail2ban-firewalld package sends bans through firewalld, which is the default firewall on those distros. Ubuntu and Debian need no extra package.

Check what you got with fail2ban-client --version. The current release is 1.1.0, from April 2024, and everything below works on 0.11 and later.

2. Put your settings in jail.local

The header of /etc/fail2ban/jail.conf tells you not to edit that file, because a package update will overwrite it. Your changes go in /etc/fail2ban/jail.local, which is read afterwards and wins.

/etc/fail2ban/jail.local
[DEFAULT]
bantime  = 1h
findtime = 10m
maxretry = 5
ignoreip = 127.0.0.1/8 ::1 203.0.113.25 2001:db8:1234::/64

[sshd]
enabled = true

The shipped defaults are bantime = 10m, findtime = 10m, maxretry = 5: five failures inside ten minutes gets an address banned for ten minutes. Ten minutes is a short ban. An hour is a more useful default.

ignoreip accepts IPv4 addresses, IPv6 addresses, CIDR ranges, and hostnames, separated by spaces. Put your own home or office address there. The server's own addresses are already ignored, because ignoreself defaults to true.

Every jail in jail.conf ships disabled, so enabled = true under [sshd] is the line that turns SSH protection on. Some distro packages enable it for you; setting it again does no harm.

3. Check which log the jail reads

This is where most installs quietly fail.

The sshd jail takes its log path from a paths file that ships with fail2ban and differs per distro. On Ubuntu and Debian it resolves to /var/log/auth.log. On AlmaLinux, Rocky, and RHEL it resolves to /var/log/secure. Some distro packages point the jail at the journal instead. Check yours:

ssh session
$ sudo fail2ban-client get sshd logpath
$ sudo systemctl status fail2ban

Debian 12 and later no longer install rsyslog, so /var/log/auth.log is never created and sshd logs to the journal. When the jail is pointed at a file that does not exist, fail2ban refuses to start it:

fail2ban log
ERROR   No file(s) found for glob /var/log/secure
ERROR   Failed during configuration: Have not found any log file for sshd jail

The fix is to move that jail to the journal:

/etc/fail2ban/jail.local
[sshd]
enabled = true
backend = systemd

Do not add logpath next to it. The systemd backend does not accept a log path, and takes its journalmatch from the filter instead.

Do not set the systemd backend for every jail

The journal always exists, so fail2ban can no longer warn you that a log file is missing. A jail for a service that writes its own log file will then find no failures and give no reason. Set the backend per jail, on the jails whose service you know logs to the journal.

4. Start it and confirm it bans

ssh session
$ sudo fail2ban-client -t
$ sudo systemctl enable --now fail2ban
$ sudo fail2ban-client status
$ sudo fail2ban-client status sshd

-t checks the configuration without touching the running service. status lists the jails that started. status sshd shows the jail's failure and ban counts, plus the addresses banned right now. On a public IPv4 address the failure count starts climbing within minutes.

If the jail is up but nothing is ever found, test the filter against your real log:

ssh session
$ sudo fail2ban-regex systemd-journal sshd
$ sudo fail2ban-regex /var/log/auth.log sshd

Use the first form for the systemd backend and the second for a file. The output counts matched and missed lines. Plenty of failed logins in the log and zero matches usually means the jail is reading the wrong source. The filter itself is rarely the problem.

5. Ban repeat offenders for longer

The same networks come back. bantime.increment multiplies the ban every time an address is banned again:

/etc/fail2ban/jail.local
[DEFAULT]
bantime.increment = true
bantime.factor = 1
bantime.maxtime = 4w

With the default formula the ban grows by 1, 2, 4, 8, 16 times the starting bantime, and bantime.maxtime caps it. Bans and ban counts are stored in /var/lib/fail2ban/fail2ban.sqlite3, so they survive a service restart and a reboot.

That history is trimmed by dbpurgeage, which defaults to one day. Raise it if you want the increment to have a longer memory:

/etc/fail2ban/fail2ban.local
[DEFAULT]
dbpurgeage = 30d

6. Unban an address

When you ban yourself, log in through the browser console in your client area and run:

ssh session
$ sudo fail2ban-client banned
$ sudo fail2ban-client set sshd unbanip 203.0.113.25
$ sudo fail2ban-client unban 203.0.113.25
$ sudo fail2ban-client unban --all

banned prints every banned address, grouped by jail. set sshd unbanip clears one address from one jail, unban clears it from every jail and from the database, and unban --all clears everything. Then add the address to ignoreip so it cannot happen twice.

What fail2ban does not cover

fail2ban bans by adding firewall rules, and on Ubuntu and Debian those land where ufw works. Docker documents that publishing a container port routes its traffic in the nat table, so packets are diverted before they reach the INPUT and OUTPUT chains ufw uses. A ban therefore has no effect on traffic to a published container port. Your sshd jail is fine, because sshd runs on the host. A jail watching a containerised web app will report bans that change nothing. Publish container ports to 127.0.0.1 and put a reverse proxy in front instead.

fail2ban also raises the cost of password guessing without removing it. Key-only SSH removes it. Use keys, and keep fail2ban for the log noise and for the services that do not have an equivalent.

Quick reference

TaskCommand
Test the config before restartingfail2ban-client -t
List running jailsfail2ban-client status
Failures and bans for a jailfail2ban-client status sshd
Which log a jail readsfail2ban-client get sshd logpath
Test the filter against a logfail2ban-regex systemd-journal sshd
List every banned addressfail2ban-client banned
Unban across all jailsfail2ban-client unban 203.0.113.25
Apply config changesfail2ban-client reload

Where to go next

fail2ban writes rules into your firewall, so set the firewall to default deny first with our firewall guide. For the rest of the baseline, the first ten minutes on a new VPS covers keys, the sudo user, and automatic security updates. DDoS protection is included on all D4 Networks plans.

fail2ban ssh security intrusion ubuntu debian almalinux rocky rhel

Related articles