Security

Use Fail2ban with firewalld or nftables ban actions

Make Fail2ban put its bans into the firewall your server really uses. Set banaction to firewalld rich rules or nftables, check the distribution defaults and confirm bans in the live ruleset.

IntermediateLinux server5 min read

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 ignoreip in /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 sshd on 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-multiport and nftables-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:

Bash
grep -r "banaction" /etc/fail2ban/jail.d/ /etc/fail2ban/jail.local 2>/dev/null

Then ask the running Fail2ban what it actually resolved. This dumps the full configuration:

Bash
sudo fail2ban-client -d | grep -i "banaction" | head

What you will typically find:

  • AlmaLinux and Rocky (EPEL): the fail2ban-firewalld package adds 00-firewalld.conf, which sets a firewalld action. Install the fail2ban metapackage or fail2ban-firewalld so this file is present.
  • Debian and Ubuntu: the default comes from jail.conf or defaults-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:

INI
[DEFAULT]
banaction = firewallcmd-rich-rules
banaction_allports = firewallcmd-rich-rules

For servers that collect thousands of bans, firewallcmd-ipset scales better, because one set is checked instead of a long list of rules:

INI
[DEFAULT]
banaction = firewallcmd-ipset
banaction_allports = firewallcmd-ipset

The ipset action needs the ipset tools available. Then apply:

Bash
sudo fail2ban-client -t && sudo systemctl restart fail2ban

A 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:

Bash
sudo fail2ban-client set sshd banip 198.51.100.20
sudo firewall-cmd --list-rich-rules

With 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:

Bash
sudo fail2ban-client set sshd unbanip 198.51.100.20

Use nftables

If you manage nftables directly and firewalld and UFW are not installed, use the nftables actions:

INI
[DEFAULT]
banaction = nftables-multiport
banaction_allports = nftables-allports

Make sure the nft command exists (sudo apt install nftables on Debian and Ubuntu) and the service is enabled:

Bash
sudo systemctl enable --now nftables
sudo fail2ban-client -t && sudo systemctl restart fail2ban

Fail2ban 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

Bash
sudo fail2ban-client set sshd banip 198.51.100.20
sudo nft list ruleset | grep -B2 -A8 f2b

You 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:

Bash
sudo nft list table inet f2b-table

Note: 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:

Bash
systemctl is-active ufw firewalld nftables

Check it works

Beyond the manual test, trigger a real ban from another network (a phone hotspot works) with a few failed SSH logins. Then:

Bash
sudo fail2ban-client status sshd
sudo grep -i "ban\|error" /var/log/fail2ban.log | tail

The address should be in the jail's banned list, in the firewall output above, and new connections from it should time out.

Troubleshooting

  • fail2ban.log shows firewall-cmd errors: firewalld is not running. Start it with sudo systemctl enable --now firewalld, after confirming SSH is allowed.
  • nftables action fails with "No such file or directory": the nft binary is missing. Install nftables.
  • 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 port is 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 to ignoreip.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.