UFW, iptables and nftables

UFW shows one set of rules, iptables -L shows another, and nft list ruleset shows a third, longer list. They are all views of the same firewall in the kernel. Once you know how they stack, the output starts to make sense.

One firewall, several tools

The firewall itself lives in the Linux kernel. Everything else is a tool that writes rules into it. On a current server you meet four names:

So on a current Ubuntu server the chain usually goes: ufw writes iptables rules, iptables-nft turns them into nftables rules, and the kernel runs those.

What your distro uses by default

Debian made nftables the default framework in Debian 10 (Buster). There, iptables uses nftables through the iptables-nft layer. Ubuntu switched with 21.04, and the 22.04 LTS release notes state that nftables is the default firewall backend.

To see which variant your iptables is, ask for its version:

sudo iptables -V

(nf_tables) after the version number means iptables-nft. (legacy) means the old backend. Debian and Ubuntu pick between them with the alternatives system, and switching back to legacy looks like this:

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

Don't switch unless a program you rely on needs it. The Ubuntu release notes put it plainly: all applications on the system must agree on one backend.

See the real ruleset

Because UFW, Docker and anything else using iptables-nft all end up in nftables, one command shows all of it:

sudo nft list ruleset

Expect a long list. Rules from iptables-nft appear in tables such as table ip filter and table ip6 filter, named after the address family and the old iptables table. UFW's chains have names starting with ufw-. Docker adds its own chains, such as DOCKER-USER. Any native nftables rules appear in their own tables, often table inet filter.

Compare with the narrower views:

If iptables-legacy is installed, its rules are in the old x_tables part of the kernel and won't show in nft list ruleset at all. Check with sudo iptables-legacy -S.

Why mixing tools confuses people

Each tool only shows and manages its own part. When two of them write rules, nobody sees the whole picture, and the results surprise you.

The key rule in nftables: when several base chains hook into the same point, a packet passes through all of them in priority order. An accept in one chain isn't final, and the packet still goes to the next. A drop is final straight away. So a port you opened with ufw allow can still be blocked by a separate nftables table that drops it. To let traffic in, every chain on the path has to agree. To block it, one chain is enough.

Other common traps:

Pick one tool and stick to it

The Debian wiki's answer to whether you should mix nftables and iptables rulesets is no, unless you know what you are doing. In practice:

Moving old iptables rules over

If you have old iptables commands from a script or a guide, iptables-translate prints the nftables version of a rule:

iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT

It prints an nft add rule command for you to check. For a whole saved ruleset, iptables-restore-translate does the same. Read the output before you load it. A firewall change over SSH is the classic way to lock yourself out, so keep a way back in ready.

Stenvakt reads the whole ruleset, not one tool's view of it. Its Review is a read-only check of every server, firewall included, and you see a Preview of any fix before it runs. Fixes run in safe mode: if a change cuts off SSH, the server rolls it back by itself. It's a Mac app and isn't out yet: get early access.

Sources

  1. Debian Wiki: nftables
  2. Ubuntu 22.04 LTS release notes
  3. xtables-nft(8) manual page (man7.org)
  4. nftables wiki: Moving from iptables to nftables
  5. nftables wiki: Configuring chains
Next guideLocked out after ufw enable