Fail2ban does not block traffic itself. When a jail bans an address, it runs a ban action that adds a rule to your firewall. If that action targets the wrong firewall, bans are recorded but never enforced. This guide shows how to choose the right action for firewalld or plain nftables, what each distribution sets by default, and how to see the bans in the live ruleset.
Before you start
- A Linux VPS with Fail2ban installed. See Install Fail2ban.
- One firewall manager in use:
- firewalld, the default on AlmaLinux and Rocky Linux. See firewalld on AlmaLinux and Rocky.
- nftables directly, common on Debian 12 when you manage rules by hand. See Get started with nftables.
- SSH already allowed in that firewall. Fail2ban's rules sit on top of your own; they do not open anything.
- Your own IP address in
ignoreipin/etc/fail2ban/jail.local.
Warning: Before you change firewalls or reload rules, confirm SSH is allowed, for example with sudo firewall-cmd --list-services or sudo nft list ruleset. If a mistake locks you out, log in through the browser console in your VPS provider's control panel, which does not depend on the firewall.
How ban actions work
Each jail has an action. By default it is %(action_)s, which runs whatever banaction names. There are two related settings:
- banaction: used for jails that block specific ports, such as
sshdon port 22. - banaction_allports: used for jails that block every port, such as
recidive.
Ban actions live in /etc/fail2ban/action.d/. The ones that matter here:
firewallcmd-rich-rules: adds one firewalld rich rule per banned address.firewallcmd-ipset: puts banned addresses in an ipset and blocks the set. Better for very large numbers of bans.nftables-multiportandnftables-allports: write to Fail2ban's own nftables table.iptables-multiport: the classic default, for iptables-based setups.
See what your system uses now
Distribution packages often set the ban action for you in /etc/fail2ban/jail.d/. Check before you change anything:
grep -r "banaction" /etc/fail2ban/jail.d/ /etc/fail2ban/jail.local 2>/dev/nullThen ask the running Fail2ban what it actually resolved. This dumps the full configuration:
sudo fail2ban-client -d | grep -i "banaction" | headWhat you will typically find:
- AlmaLinux and Rocky (EPEL): the
fail2ban-firewalldpackage adds00-firewalld.conf, which sets a firewalld action. Install thefail2banmetapackage orfail2ban-firewalldso this file is present. - Debian and Ubuntu: the default comes from
jail.confordefaults-debian.conf, depending on the package version. Recent packages may already use nftables. Do not assume; read the output above.
Use firewalld
If firewalld is running (sudo firewall-cmd --state prints running), set the action in /etc/fail2ban/jail.local:
[DEFAULT]
banaction = firewallcmd-rich-rules
banaction_allports = firewallcmd-rich-rulesFor servers that collect thousands of bans, firewallcmd-ipset scales better, because one set is checked instead of a long list of rules:
[DEFAULT]
banaction = firewallcmd-ipset
banaction_allports = firewallcmd-ipsetThe ipset action needs the ipset tools available. Then apply:
sudo fail2ban-client -t && sudo systemctl restart fail2banA restart, rather than a reload, makes sure old rules from the previous action are removed cleanly.
Confirm bans in firewalld
Ban a documentation address by hand to test:
sudo fail2ban-client set sshd banip 198.51.100.20
sudo firewall-cmd --list-rich-rulesWith rich rules you should see a line naming 198.51.100.20 with a reject or drop. Fail2ban adds these as runtime rules, so they do not show with --permanent and disappear when firewalld reloads. Fail2ban restores its bans when it restarts.
Remove the test ban:
sudo fail2ban-client set sshd unbanip 198.51.100.20Use nftables
If you manage nftables directly and firewalld and UFW are not installed, use the nftables actions:
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allportsMake sure the nft command exists (sudo apt install nftables on Debian and Ubuntu) and the service is enabled:
sudo systemctl enable --now nftables
sudo fail2ban-client -t && sudo systemctl restart fail2banFail2ban creates its own table, so it never edits your rules in /etc/nftables.conf. Its rules drop banned addresses before your own input chain allows them.
Confirm bans in nftables
sudo fail2ban-client set sshd banip 198.51.100.20
sudo nft list ruleset | grep -B2 -A8 f2bYou should see a table named like inet f2b-table, a set for the jail such as addr-set-sshd, and 198.51.100.20 among its elements. To list one table:
sudo nft list table inet f2b-tableNote: If you reload your own ruleset with nft -f /etc/nftables.conf and that file starts with flush ruleset, Fail2ban's table is wiped too. Restart Fail2ban afterwards so it rebuilds its table and bans.
Remove the test ban when done.
Do not mix firewall managers
Run exactly one of UFW, firewalld or a hand-written nftables ruleset. Two managers fight over the same kernel tables, and a ban action written for one can be ignored or flushed by the other. Check for running services:
systemctl is-active ufw firewalld nftablesCheck it works
Beyond the manual test, trigger a real ban from another network (a phone hotspot works) with a few failed SSH logins. Then:
sudo fail2ban-client status sshd
sudo grep -i "ban\|error" /var/log/fail2ban.log | tailThe address should be in the jail's banned list, in the firewall output above, and new connections from it should time out.
Troubleshooting
fail2ban.logshowsfirewall-cmderrors: firewalld is not running. Start it withsudo systemctl enable --now firewalld, after confirming SSH is allowed.- nftables action fails with "No such file or directory": the
nftbinary is missing. Installnftables. - Bans vanish after a firewall reload: your reload flushed Fail2ban's rules. Restart Fail2ban after reloading the firewall.
- Banned addresses still connect: a different firewall is in charge, or the jail's
portis wrong. See Fail2ban not banning?. - You banned yourself: use your VPS provider's browser console, run
sudo fail2ban-client unban YOUR_IP, and add your IP toignoreip.
Next steps
- Tune your jails: Configure Fail2ban jails: bantime, findtime and maxretry.
- Write your own IP rules in firewalld: firewalld rich rules for IP-based access.
- Block whole lists of addresses: Block thousands of IPs with firewalld ipsets.
- Run it on a Linux VPS with full root access.
