Migrating from iptables to nftables isn’t just a syntax change; it’s a fundamental shift in how your firewall operates, offering a more unified and efficient framework.
Let’s see nftables in action with a common scenario: allowing SSH traffic from a specific IP address while blocking everything else.
# First, flush existing rules (use with caution in production!)
nft flush ruleset
# Create a new table named 'inet filter' (handles IPv4 and IPv6)
nft add table inet filter
# Add a chain named 'input' for incoming traffic
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# Add a rule to accept SSH (TCP port 22) from 192.168.1.100
nft add rule inet filter input ip saddr 192.168.1.100 tcp dport 22 accept
# Add a rule to accept established/related connections
nft add rule inet filter input ct state established,related accept
# List the current ruleset to verify
nft list ruleset
This set of commands establishes a basic firewall. The inet family means it handles both IPv4 and IPv6. The filter table is a logical grouping, and the input chain is where packets destined for the local machine are processed. The policy drop on the input chain means any packet not explicitly allowed will be discarded. The rules then selectively permit SSH from a trusted source and allow return traffic for established connections.
The core problem nftables solves is the fragmentation and complexity of the Linux netfilter subsystem, which iptables has historically managed. iptables uses separate tools (iptables, ip6tables, arptables, ebtables) for different protocols and layers, leading to duplicated rules and an inconsistent user experience. nftables unifies this into a single tool and a more structured rule language.
Internally, nftables uses a bytecode interpreter. Instead of kernel modules for each tool, nftables compiles its rules into bytecode that the netfilter kernel module executes. This makes rule evaluation faster because the kernel doesn’t need to traverse separate rule chains for different address families. The nft command-line utility communicates with the netfilter subsystem to load these bytecode programs.
The fundamental levers you control are tables, chains, and rules.
- Tables: Containers for chains. You can have tables for different families (
ip,ip6,inet,arp,bridge,netdev) or custom tables.inetis often preferred as it covers both IPv4 and IPv6. - Chains: Sequences of rules that process packets. They are attached to "hooks" in the kernel’s network stack (e.g.,
prerouting,input,forward,output,postrouting). Chains have types (filter,nat,route) and priorities. - Rules: The actual instructions. Each rule specifies a set of criteria (e.g., source IP, destination port, protocol, connection state) and an action (
accept,drop,reject,masquerade,redirect).
The nftables rule language is designed to be expressive and efficient. It supports complex matching expressions and allows for advanced features like sets, maps, and quotas directly within the ruleset. For instance, you can define a set of IPs and then match against that set in a single rule, rather than having individual rules for each IP.
When you define a chain with a policy drop, it doesn’t mean the kernel actively scans for packets to drop. Instead, it signifies the default action for any packet that traverses the chain and doesn’t match an explicit accept or reject rule. The kernel simply moves on to the next packet if no matching rule is found, and the implicit drop is the outcome of exhausting all rules without a positive match.
The next concept you’ll likely encounter is managing stateful firewalling and Network Address Translation (NAT) with nftables, as these are common and powerful use cases.