nftables will eventuelly replace iptables as the Linux kernel packet classification framework, more comply referred to as ‘the firewall’. Both are still maintained, and will be for a while. So which one should you choose?

Well obviously, nftables replacing iptables, the answer is nftables, at least in the long run. nftables has a number of advantages, for me, the most important are:

  • Unified rule for IPv4 and IPv61: rules which are independent of IP protocol, such as ‘allow traffic on TCP port 22’ can be writen in such a way that a single rule applies to both protocols
  • Increased security and performance2: rules get translated into bytecode, which is then executed by a simple virtual machine, at least in theory, this should be both more secure and faster
  • Dynamic sets3: changing allow or droplist, and even port mapping can be done without updating the firewall rules themselves

There are also a number of disadvantages:

  • Maturity: nftables, although very mature already, can still lack some of the features which are standard in iptables, especially when using the version included in stable distributions, more on this later
  • Tooling: many tools exist for iptables, for example the excellent Shorewall is specifically written for iptables, although the more powerful syntax of nftables makes the use of tooling to manage rules less necessary
  • Documentation: personally I find it easier to find docmentation and examples for iptables than for nftables, I hope to improve this situation with some future blog posts

Whether the advantages outway the disadvantages actually depends on the version of the Linux kernel and the nftables userspace tools used. Since these are tied to Linux distribution, it depends on which version you are running. Since I am most familiar with Debian I will limited this discussion to that distribution4.

Debian 9 “Stretch”

Initially released in 2017, Stretch uses iptables by default. nftables can be installed, however the stretch package itself recommends using at least Linux 4.105, while Stretch comes with 4.96. Therefor I recommand sticking with iptables.

Debian 10 “Buster”

Buster, by default, installes iptables, but with nftables as the backend. This is possible because nftables provides implementation of the main iptables userland tools (iptables, ip6tables, arptables, ebtables) which automatically translate iptables rules to nftables rules7.

While this is a great as a default because it allows transitioning to a new framework, while maintaining compatibility with the old, this provides the ‘worst of both worlds’ in the sense that not all iptables features are supported by nftables8 and new nftables features cannot be used this way.

It is possible to switch to nftables completely with a simple

# aptitude install nftables
# systemctl enable nftables.service

however I have encountered a number of limitations while running nftables on Buster:

  • Connection tracking on bridges is not supported9: this might not be a problem when running a simple server, however when running a host for KVM or Docker virtual machines this is a significant limitation, one that can be worked around10, at the cost of reducing security
  • All basic functionality is supported, however when combining certain features unexpected errors can occur, for example using concatenations for ICMP codes like this
    # nft add set inet filter allowed_icmp { type icmp_type . icmp_code\; };
    # nft add rule inet filter input icmp code . icmp type @allowed_icmp accept

    results in the following error on Buster

    Error: can not use variable sized data types (integer) in concat expressions

    but works perfectly fine on Bullseye

Therefore, I recommend getting familiar with nftables on test systems, but using iptables on production systems.

Switch to iptables is as easy as11

# update-alternatives --set iptables /usr/sbin/iptables-legacy
# update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
# update-alternatives --set arptables /usr/sbin/arptables-legacy
# update-alternatives --set ebtables /usr/sbin/ebtables-legacy

Debian 11 “Bullseye”

At the moment I am writing this blog, Bullseye has not been released yet. Although it is in ‘Hard Freeze’12 and expected in Summer 202113. However you can install RC 114 and easily update once it becomes final.

On Bullseye all problems I personally encountered with nftables have been resolved. Bullseye uses the latest Linux LTS kernel version 5.10 as well as a very up-to-date version of the userspace tools.

Therefore, on Bullseye, I recommend considering dropping iptables all together and going for nftables natively. Do test whether all your packages are compatible, taking into account that certain packages (e.g. qemu-kvm or docker) tend to attempt to automatically configure the firewall.

I hope this blog post helped you out. If it did or you have some remarks feel free to drop a note. Several ways of contacting me are linked at the bottom of this page.

  1. See the ‘inet’ nftables family 

  2. The return of nftables 

  3. Named sets with the ‘dynamic’ flag set 

  4. Although older versions of Debian can use newer versions of the nftables userspace (or even newer kernels) through backports these generally don’t receive security updates with the same timeliness as the ‘vanilla’ distribution, therefore I will leave them out of the discussion 





  9. Connection tracking on bridges is supported since Linux 5.3, see Stateful filtering 

  10. Instead of connecting tracking it is possible to limit all TCP packages with the ‘SYN’ flag, however this is less secure and doesn’t work for UDP