nftables: Modern Linux Firewalling

For nearly two decades, iptables was the standard way to configure the Linux firewall. While it is still widely used, modern Linux distributions are increasingly adopting nftables as the preferred packet filtering framework.

Unlike iptables, which evolved over many years through multiple utilities and extensions, nftables was designed as a clean replacement with a simpler architecture, better performance, and greater flexibility.

If you're starting with a modern Linux distribution such as Debian 12, Ubuntu 24.04, Fedora, or RHEL 9, there is a good chance that your firewall is already powered by nftables, even if you still use the iptables command.

In this chapter, you'll learn how nftables is organized, how to write firewall rules, and how to build practical firewalls using its native syntax.


Why nftables?

As Linux networking evolved, the limitations of iptables became increasingly apparent.

Some of its challenges included:

  • separate tools for IPv4 and IPv6,
  • duplicated rule sets,
  • multiple independent utilities (iptables, ip6tables, ebtables, arptables),
  • inefficient rule evaluation in large firewalls,
  • inconsistent syntax between features.

To address these issues, the Linux kernel introduced nftables.

The goals were:

  • one framework for all protocol families,
  • simpler syntax,
  • more flexible rule matching,
  • better performance,
  • easier maintenance.

Today, nftables is considered the future of Linux firewalling.


nftables Architecture

Like iptables, nftables configures the netfilter framework.

However, its internal organization is more flexible.

Instead of predefined tables and chains, you create them yourself.

The hierarchy is:

Tables
    └── Chains
            └── Rules

Unlike iptables, chains are explicitly connected to netfilter hooks when they are created.


Tables

A table groups related chains.

Create a table:

sudo nft add table inet firewall

List tables:

sudo nft list tables

Example:

table inet firewall

Notice the protocol family:

  • ip
  • ip6
  • inet
  • arp
  • bridge
  • netdev

The inet family is especially useful because one rule set can filter both IPv4 and IPv6 traffic.


Chains

Unlike iptables, chains are not predefined.

You create them and specify:

  • which hook they attach to,
  • their priority,
  • and their default policy.

Example:

sudo nft add chain inet firewall input \
'{ type filter hook input priority 0; policy accept; }'

This creates a chain attached to the INPUT hook.

The important fields are:

  • type — filter, nat, route
  • hook — input, output, forward, prerouting, postrouting
  • priority — execution order relative to other chains
  • policy — default action

Rules

Rules are added to chains.

Example:

sudo nft add rule inet firewall input tcp dport 22 accept

Breaking it down:

  • tcp
  • destination port 22
  • action accept

The syntax is intentionally close to natural language.

Another example:

sudo nft add rule inet firewall input icmp accept

Listing the Ruleset

Display the complete configuration:

sudo nft list ruleset

Example:

table inet firewall {
    chain input {
        type filter hook input priority 0;
        policy accept;

        tcp dport 22 accept
        icmp accept
    }
}

Unlike iptables, a single command displays the entire ruleset.


Rule Evaluation

Packets are evaluated sequentially.

For example:

tcp dport 22 accept
icmp accept
drop

If an SSH packet arrives:

  • rule 1 matches
  • evaluation stops
  • packet is accepted

If an HTTP packet arrives:

  • rule 1 fails
  • rule 2 fails
  • final rule drops the packet

Just like iptables, rule order matters.


Matches

Rules can match many packet attributes.

Examples include:

Match protocol:

tcp

Match source address:

ip saddr 192.168.1.100

Match destination address:

ip daddr 10.0.0.5

Match source port:

tcp sport 443

Match destination port:

tcp dport 80

Multiple conditions can be combined naturally.


Hands-on Lab: Create Your First Firewall

Warning

Perform these exercises on a virtual machine. Incorrect firewall rules can interrupt remote access.


Step 1

Create a table.

sudo nft add table inet firewall

Step 2

Create an input chain.

sudo nft add chain inet firewall input \
'{ type filter hook input priority 0; policy drop; }'

Notice that the default policy is now drop.


Step 3

Allow loopback traffic.

sudo nft add rule inet firewall input iif lo accept

Many applications rely on loopback communication.


Step 4

Allow established connections.

sudo nft add rule inet firewall input ct state established,related accept

This rule depends on connection tracking, which you learned in the previous chapter.

Without it, replies to existing connections would be blocked.


Step 5

Allow SSH.

sudo nft add rule inet firewall input tcp dport 22 accept

Step 6

Allow ICMP.

sudo nft add rule inet firewall input icmp accept

Display the final configuration:

sudo nft list ruleset

Your ruleset should resemble:

table inet firewall {
    chain input {
        policy drop;

        iif lo accept
        ct state established,related accept
        tcp dport 22 accept
        icmp accept
    }
}

You now have a simple stateful firewall.


Sets

One of the most powerful features of nftables is sets.

Instead of writing multiple nearly identical rules:

tcp dport 22 accept
tcp dport 80 accept
tcp dport 443 accept

Create a single rule:

sudo nft add rule inet firewall input tcp dport {22,80,443} accept

This is easier to read and scales much better.

Sets are one of the biggest advantages of nftables over iptables.


Counters

Rules can maintain packet counters.

Example:

sudo nft add rule inet firewall input counter tcp dport 22 accept

Display them:

sudo nft list ruleset

Example:

counter packets 120 bytes 9120

Counters are useful for verifying whether a rule is actually matching traffic.


Logging

To log matching packets:

sudo nft add rule inet firewall input log prefix "INPUT: "

Kernel logs can be viewed using:

journalctl -k

Logging is invaluable when diagnosing firewall behavior.


Deleting Rules

Each rule has a handle number.

Display handles:

sudo nft -a list ruleset

Example:

tcp dport 22 accept # handle 12

Delete it:

sudo nft delete rule inet firewall input handle 12

Flushing Rules

Remove every rule from a table:

sudo nft flush table inet firewall

Delete the table completely:

sudo nft delete table inet firewall

Saving the Configuration

Like iptables, nftables rules exist in kernel memory.

To save them:

sudo nft list ruleset > firewall.nft

Load them again:

sudo nft -f firewall.nft

Most Linux distributions provide a system service that automatically loads a saved configuration during boot. The exact file location and service name vary between distributions.


nftables vs iptables

Featureiptablesnftables
Initial release19982014
IPv4 and IPv6Separate toolsUnified (inet)
Rule syntaxOlderCleaner
Multiple utilitiesYesNo
SetsLimitedNative support
Rule managementIndividual commandsUnified ruleset
Future developmentMaintenanceActive development

The concepts remain the same because both configure the same netfilter framework.

The difference lies in usability and architecture.


Common Mistakes

Forgetting Loopback

Applications frequently communicate through 127.0.0.1.

Blocking loopback can cause unexpected failures.

Always allow it explicitly.


Omitting Established Connections

Without:

ct state established,related accept

return traffic is often blocked.

This is one of the most common mistakes when creating a firewall from scratch.


Forgetting the Default Policy

If your chain policy is drop, only explicitly allowed traffic will pass.

This is generally a good security practice, but it requires careful testing.


Editing Production Firewalls Blindly

Always keep an alternative management path, such as:

  • a virtual machine console,
  • out-of-band management,
  • or a second SSH session.

This reduces the risk of locking yourself out.


Best Practices

  • Prefer the inet family whenever possible.
  • Build stateful firewalls using connection tracking.
  • Use sets instead of repetitive rules.
  • Keep rules ordered from most specific to most general.
  • Monitor counters during troubleshooting.
  • Test firewall changes incrementally.
  • Store firewall rules in version control.

A firewall should be predictable, readable, and easy to audit.


Looking Ahead

So far, we have explored how Linux processes packets, how netfilter provides hook points inside the kernel, and how both iptables and nftables configure packet filtering.

The remaining challenge is understanding why packets are accepted or dropped when something goes wrong.

In the next chapter, we will learn how to trace packets through the Linux networking stack, identify where they are being processed, and use debugging tools to troubleshoot complex networking problems.


Summary

  • nftables is the modern userspace interface for configuring the Linux netfilter framework.
  • It replaces the older iptables family with a unified and more flexible design.
  • Rules are organized into tables, chains, and rules, but chains are explicitly attached to netfilter hooks.
  • The inet family allows a single ruleset to filter both IPv4 and IPv6 traffic.
  • Stateful firewalls rely on connection tracking through ct state.
  • Sets make rule definitions more compact and efficient.
  • Rule counters and logging are valuable tools for debugging.
  • nftables is the recommended choice for new Linux deployments, while understanding iptables remains important for maintaining existing systems.