In Linux network engineering, edge gateway administration, and container virtualization, fine-grained control over packet routing, address translation, and port redirection is essential. The Linux kernel processes all network I/O through the Netfilter subsystem. For decades, the legacy iptables utility served as the primary interface for managing Netfilter tables and chains. Modern Linux distributions have transitioned to nftables, which delivers higher packet throughput, a unified syntax across IPv4 and IPv6, atomic rule commits, and reduced CPU overhead. Mastering both iptables and nftables enables network engineers to configure stateful inspection, source NAT masquerading, and robust port forwarding architectures.
Architectural Evolution: iptables vs. nftables
While both utilities configure the Netfilter kernel framework, nftables eliminates the fragmented codebase of iptables, ip6tables, arptables, and ebtables. The table below delineates the structural differences between both tools:
| Architectural Dimension | Legacy iptables Utility | Modern nftables Framework |
|---|---|---|
| Address Family Support | Fragmented binaries (iptables for IPv4, ip6tables for IPv6). |
Unified inet family processes both IPv4 and IPv6 within a single ruleset. |
| Table & Chain Architecture | Fixed, hardcoded tables (filter, nat, mangle, raw). |
Completely dynamic; administrators create arbitrary tables and attach custom chains. |
| Rule Update Mechanism | Non-atomic; re-evaluates the entire rule table sequentially upon mutation. | Fully atomic; rulesets compile and commit in a single transactional kernel step. |
| Connection Tracking Overhead | Heavy reliance on external xt_conntrack match modules. |
Native internal state machine matching directly in the bytecode engine. |
| Set / Dictionary Support | Requires external ipset tooling for large IP matching arrays. |
Native high-speed hash tables, sets, and interval maps built directly into syntax. |
Managing Packet Filtering with iptables
In iptables, packets traverse predefined tables containing chains (INPUT, FORWARD, OUTPUT). Rules are evaluated linearly.
1. Establishing a Hardened Baseline with Stateful Tracking
To establish a secure baseline on an internet-facing interface (e.g., eth0), allow loopback traffic and established connections, then drop all unsolicited ingress:
# Set default chain policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT
# Allow unrestricted localhost loopback traffic
sudo iptables -A INPUT -i lo -j ACCEPT
# Stateful inspection: Allow packets belonging to established or related connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow inbound SSH on port 22
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
2. Configuring Source NAT (Masquerading) for a Gateway Router
When turning a dual-NIC Linux server into an office router where eth0 connects to the WAN and eth1 connects to the private LAN (192.168.10.0/24):
# Enable IPv4 packet forwarding in the kernel
sudo sysctl -w net.ipv4.ip_forward=1
# Masquerade outgoing private packets with the WAN IP
sudo iptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/24 -j MASQUERADE
# Forward packets between LAN and WAN
sudo iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
3. Destination NAT (Port Forwarding)
To redirect incoming HTTP traffic hitting the WAN port 80 to an internal web server at 192.168.10.50:8080:
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.10.50:8080
sudo iptables -A FORWARD -p tcp -d 192.168.10.50 --dport 8080 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
Configuring Advanced Rulesets with nftables
The nft utility replaces disparate match extensions with clean, human-readable syntax and native set operations.
Step 1: Create a Dynamic Dual-Stack Table
In nftables, tables must be explicitly declared. Creating an inet table processes both IPv4 and IPv6 traffic concurrently:
# Create the master filter table
sudo nft add table inet filter
# Create base ingress and forward chains hooked to Netfilter pipeline
sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
sudo nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
sudo nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
Step 2: Add Filtering Rules with Native Sets
Rather than writing multiple individual rules for separate ports, nftables accepts curly-brace set arrays:
# Accept loopback traffic
sudo nft add rule inet filter input iif "lo" accept
# Accept established and related connections
sudo nft add rule inet filter input ct state established,related accept
# Drop invalid packets
sudo nft add rule inet filter input ct state invalid drop
# Authorise SSH, HTTP, and HTTPS simultaneously in a single rule
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } ct state new accept
Step 3: Implementing NAT in nftables
To configure NAT masquerading and port forwarding in nftables:
# Create dedicated NAT table and hooks
sudo nft add table ip nat
sudo nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
sudo nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
# Masquerade outgoing LAN traffic
sudo nft add rule ip nat postrouting oif "eth0" ip saddr 192.168.10.0/24 masquerade
# Port forward WAN port 443 to internal container
sudo nft add rule ip nat prerouting iif "eth0" tcp dport 443 dnat to 10.0.3.15:8443
Translating and Persisting Rulesets
To migrate existing legacy rules without manual rewriting, utilize the translation utility:
# Translate an individual iptables command to nftables syntax
iptables-translate -A INPUT -p tcp --dport 80 -j ACCEPT
# Output: nft add rule ip filter INPUT tcp dport 80 counter accept
# Save active nftables configuration for boot persistence
sudo nft list ruleset > /etc/nftables.conf
# Enable systemd boot service
sudo systemctl enable --now nftables
Troubleshooting Packet Drops and Inspection Failures
When packets fail to traverse firewalls or routing loops occur, apply the following diagnostic techniques:
- Monitoring Drops in Real Time via Trace: In
nftables, you can tag packets for packet-level kernel tracing:
The terminal streams the exact chain, table, and verdict applied to each incoming packet.sudo nft add rule inet filter input tcp dport 22 meta nftrace set 1 sudo nft monitor trace - Forwarding Blocked by Kernel Flags: If NAT rules are configured correctly but packets fail to exit the server, verify that IPv4 forwarding is active:
If it returnscat /proc/sys/net/ipv4/ip_forward0, packet routing is disabled at the kernel level. Persist activation by settingnet.ipv4.ip_forward=1inside/etc/sysctl.confand runningsudo sysctl -p. - iptables and nftables Conflicts: Running legacy
iptablescommands alongside nativenftablesdaemons can cause unexpected double-filtering. On modern Ubuntu systems, ensureiptablespoints to theiptables-nftcompatibility layer viasudo update-alternatives --config iptables.