How to Configure nftables Stateful Firewalls, Dynamic Sets, and Flowtables on Ubuntu Server

For more than two decades, Linux system administrators relied on iptables, ip6tables, and arptables to construct host firewalls and network routing policies. However, the legacy iptables architecture suffered from severe structural limitations: disparate tools for IPv4 and IPv6, linear rule-evaluation bottlenecks that degraded performance under large rulesets, and race conditions during live updates. The upstream Linux kernel community engineered nftables to fundamentally replace the entire legacy iptables framework.

Operating as a unified pseudo-state virtual machine directly inside the Netfilter kernel substrate, nftables merges dual-stack IPv4/IPv6 packet filtering into a single ruleset. By pairing stateful connection tracking (conntrack) with Dynamic Sets (enabling self-expiring IP ban-lists) and Flowtables (which bypass standard routing pipelines for established connections), Ubuntu Server administrators can build enterprise-grade firewalls capable of filtering millions of packets per second with minimal CPU utilisation.

Architectural Overview: The nftables Virtual Machine and Hook Pipeline

nftables processes packets via a deterministic internal bytecode engine attached to Netfilter net-hooks:

Component Technical Architecture Operational Function
nftables VM In-Kernel Bytecode Interpreter Executes compiled filter expressions in a single contiguous pass; eliminates multiple table jumps.
Dual-Stack inet Family Unified IPv4 / IPv6 Address Filter Applies firewall rules across both IP versions simultaneously, eliminating rule duplication.
Base Chains Netfilter Hook Bindings Attaches to kernel entry points (prerouting, input, forward, output, postrouting) with explicit priority ordering.
Dynamic Sets & Dictionaries O(1) Hash / Tree Lookup Structures Performs instant lookups against thousands of IPs, ports, or MAC addresses; supports auto-expiring timeouts.
Flowtable Fastpath Hardware/Software Bypass Pipeline Bypasses TCP/IP stack evaluation for verified established connections, delivering line-rate wire speed.

Installing nftables and Disabling Legacy Firewalls on Ubuntu

Ubuntu Server includes nftables natively. Before activating it, disable conflicting legacy services such as Uncomplicated Firewall (UFW) or iptables wrappers.

Step 1: Disable Legacy Firewall Services

# Disable UFW to prevent netfilter hook collisions
sudo ufw disable
sudo systemctl stop ufw
sudo systemctl disable ufw

Step 2: Install nftables and Enable the Systemd Service

# Install nftables and verify utility binaries
sudo apt update
sudo apt install -y nftables

# Enable and start the systemd unit
sudo systemctl enable nftables
sudo systemctl start nftables

Authoring a Hardened Stateful Ruleset in /etc/nftables.conf

The primary ruleset file is loaded by systemd at boot from /etc/nftables.conf. Open the configuration file in a text editor:

sudo nano /etc/nftables.conf

Replace the contents with the following production-grade stateful configuration:

#!/usr/sbin/nft -f

# Flush any existing rules from memory
flush ruleset

# Define unified IPv4/IPv6 filtering table
table inet filter {

    # Dynamic Set: Stores auto-expiring malicious IPs
    set autoban_v4 {
        type ipv4_addr
        size 65535
        flags timeout
    }

    # Flowtable: Fastpath routing between dual network adapters
    flowtable ft {
        hook ingress priority filter
        devices = { eth0, eth1 }
    }

    # Inbound Traffic Chain
    chain input {
        type filter hook input priority filter; policy drop;

        # Accept all traffic on loopback interface
        iifname "lo" accept

        # Drop invalid connection states immediately
        ct state invalid drop

        # Accept established and related return traffic
        ct state { established, related } accept

        # Check and drop blacklisted addresses
        ip saddr @autoban_v4 drop

        # Allow ICMP (Ping) with rate-limiting to prevent flood attacks
        ip protocol icmp icmp type echo-request limit rate 5/second accept
        ip6 nexthdr icmpv6 icmpv6 type echo-request limit rate 5/second accept

        # Rate-limited SSH protection (Add to autoban if > 5 attempts per minute)
        tcp dport 22 ct state new meter ssh_flood { ip saddr ct count over 5 } update @autoban_v4 { ip saddr timeout 10m } drop
        tcp dport 22 ct state new accept

        # Allow Public Web Services (HTTP / HTTPS)
        tcp dport { 80, 443 } ct state new accept
    }

    # Forwarding Chain (Routing between interfaces)
    chain forward {
        type filter hook forward priority filter; policy drop;

        # Offload established bidirectional traffic to the fastpath flowtable
        ip protocol { tcp, udp } flow offload @ft

        # Accept established routed connections
        ct state { established, related } accept
    }

    # Outbound Traffic Chain
    chain output {
        type filter hook output priority filter; policy accept;
    }
}

Validating Syntax and Committing the Ruleset

To avoid locking yourself out of a remote server over SSH, always lint your configuration before committing changes to the kernel.

Step 1: Lint Configuration Syntax

# Check configuration syntax without applying rules
sudo nft -c -f /etc/nftables.conf

If the command exits silently, the ruleset syntax is valid.

Step 2: Load the Active Ruleset

# Apply configuration atomically into the Linux kernel
sudo nft -f /etc/nftables.conf

Managing Dynamic Sets and Monitoring Live Kernel Events

One of nftables’ most powerful features is managing IP sets dynamically from userland without reloading the entire ruleset.

Step 1: Inspect the Active Ruleset and Sets

# Display the complete active ruleset with byte/packet counters
sudo nft list ruleset

# Inspect the active autoban set to view temporarily blocked IPs
sudo nft list set inet filter autoban_v4

Step 2: Manually Add or Delete an IP from the Set

# Add a suspicious IP with an automated 1-hour expiration
sudo nft add element inet filter autoban_v4 { 203.0.113.88 timeout 1h }

# Remove an IP manually
sudo nft delete element inet filter autoban_v4 { 203.0.113.88 }

Step 3: Monitor Real-Time Netfilter Events

Open a secondary terminal session to trace real-time packet drops and set updates:

# Monitor live packet evaluation events
sudo nft monitor

Troubleshooting nftables Deployment and Hook Collisions

Consult this diagnostic reference table to debug syntax errors and dropped connections:

Issue Underlying Root Cause Remediation Procedure
Error: Could not process rule: No such file or directory Kernel missing required Netfilter modules (e.g. nft_flow_offload or nf_tables). Load missing kernel modules via sudo modprobe nft_flow_offload nf_tables. Ensure Linux kernel is updated.
SSH connection severs immediately upon applying rules. The input chain dropped existing SSH sessions because ct state { established, related } accept was omitted or placed below drop rules. Ensure connection tracking rule appears at the very top of the input chain before any default drop policies.
Rules are lost after server reboot. Modifications were applied via command-line nft add rule without saving to /etc/nftables.conf. Export the active running ruleset to disk: sudo nft list ruleset > /etc/nftables.conf.
Flowtable fails to bind: Error: Device eth1 does not exist. Flowtable definition referenced a network interface name that has changed or is not yet initialized at boot. Verify adapter names via ip link. Update device arrays inside the flowtable definition block.

Deploying nftables stateful rulesets, dynamic auto-expiring sets, and flowtable fastpaths establishes a high-performance network security perimeter on Ubuntu Server, outperforming legacy firewall architectures in speed, flexibility, and memory efficiency.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.