Firewall Rules: iptables and nftables

Linux packet filtering has evolved significantly over the past two decades. At its core sits the netfilter framework, a kernel subsystem that intercepts and manipulates network packets. While...

Key Insights

  • iptables remains widely deployed but nftables offers superior performance through better kernel integration, atomic rule updates, and a more consistent syntax that eliminates the need for separate tools like iptables, ip6tables, and arptables.
  • Both systems use the same netfilter kernel framework—your choice affects only the userspace interface, not packet filtering capabilities, making migration a matter of syntax translation rather than feature loss.
  • Start with iptables if working on legacy systems or following existing documentation, but choose nftables for new deployments to benefit from simplified rule management and better scripting capabilities.

Introduction to Linux Packet Filtering

Linux packet filtering has evolved significantly over the past two decades. At its core sits the netfilter framework, a kernel subsystem that intercepts and manipulates network packets. While netfilter handles the actual filtering, userspace tools like iptables and nftables provide the interface for defining rules.

iptables has been the standard since 2001, replacing ipchains and ipfwadm. Despite its ubiquity, iptables suffers from architectural limitations: separate binaries for IPv4, IPv6, and ARP filtering, inefficient rule updates requiring full table replacement, and inconsistent syntax across different table types.

nftables, introduced in kernel 3.13 (2014) and considered stable since kernel 4.14 (2017), addresses these shortcomings. It provides a unified interface for all protocol families, atomic ruleset updates, and improved performance through better data structures. The transition hasn’t been immediate—many distributions still default to iptables for compatibility—but nftables represents the future of Linux firewalling.

Choose iptables when maintaining existing systems, following established documentation, or requiring compatibility with older kernels. Choose nftables for new deployments, complex rulesets requiring frequent updates, or environments where performance matters at scale.

iptables Fundamentals

iptables organizes rules into tables, each serving a specific purpose. The filter table handles packet acceptance/rejection, nat manages network address translation, mangle modifies packet headers, and raw configures connection tracking exemptions.

Within each table, chains define decision points in packet processing. Built-in chains like INPUT (incoming packets), OUTPUT (locally generated packets), and FORWARD (routed packets) process traffic automatically. Custom chains allow rule organization and reusability.

Here’s a basic firewall allowing SSH and HTTP while blocking everything else:

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT

# Allow SSH and HTTP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Allow ICMP (ping)
iptables -A INPUT -p icmp -j ACCEPT

For NAT configuration, such as masquerading a private network:

# Enable IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward

# Masquerade outgoing traffic
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Forward traffic from internal network
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

The -A flag appends rules, -I inserts at a specific position, and -D deletes. Rules are evaluated top-to-bottom until a match occurs, making order critical.

nftables: The Modern Approach

nftables consolidates IPv4, IPv6, ARP, and bridge filtering into a single tool with consistent syntax. Instead of predefined tables and chains, you create them explicitly, providing greater flexibility in organizing rules.

The syntax emphasizes readability and scriptability. Here’s the previous iptables firewall in nftables:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        
        # Allow established/related connections
        ct state established,related accept
        
        # Allow loopback
        iif lo accept
        
        # Allow SSH and HTTP
        tcp dport { 22, 80 } accept
        
        # Allow ICMP
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Notice the inet family handles both IPv4 and IPv6, eliminating duplicate rules. Sets ({ 22, 80 }) group related values, reducing rule count. The entire ruleset can be atomically replaced by running the script.

For NAT, nftables uses similar concepts with cleaner syntax:

table inet nat {
    chain postrouting {
        type nat hook postrouting priority 100;
        oif eth0 masquerade
    }
    
    chain prerouting {
        type nat hook prerouting priority -100;
    }
}

Practical Firewall Configurations

A production firewall requires stateful inspection, rate limiting, and application-specific rules. Here’s a complete iptables configuration:

#!/bin/bash

# Flush existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X

# Default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT

# Connection tracking
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Rate limit SSH to prevent brute force
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -m recent --update --seconds 60 --hitcount 4 -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Web services
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

# DNS (if running a resolver)
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j ACCEPT

# ICMP with rate limiting
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 5 -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

# Log dropped packets
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 7

The equivalent nftables configuration demonstrates its expressiveness:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
    set ratelimit_ssh {
        type ipv4_addr
        flags dynamic, timeout
        timeout 60s
    }
    
    chain input {
        type filter hook input priority 0; policy drop;
        
        iif lo accept
        ct state invalid drop
        ct state established,related accept
        
        # SSH rate limiting
        tcp dport 22 ct state new add @ratelimit_ssh { ip saddr limit rate over 4/minute } drop
        tcp dport 22 accept
        
        # Web services
        tcp dport { 80, 443 } accept
        
        # DNS
        udp dport 53 accept
        tcp dport 53 accept
        
        # ICMP rate limiting
        icmp type echo-request limit rate 1/second burst 5 packets accept
        
        # Logging
        limit rate 5/minute log prefix "nftables-dropped: "
    }
    
    chain forward {
        type filter hook forward priority 0; policy drop;
    }
    
    chain output {
        type filter hook output priority 0; policy accept;
    }
}

Debugging and Monitoring

Understanding what your firewall is doing requires visibility into active rules and packet flow. For iptables:

# List all rules with packet counters
iptables -L -n -v

# List rules with line numbers
iptables -L INPUT --line-numbers

# Show NAT rules
iptables -t nat -L -n -v

# Reset counters
iptables -Z

# Watch dropped packets in real-time
tail -f /var/log/kern.log | grep "iptables-dropped"

For nftables:

# List entire ruleset
nft list ruleset

# List specific table
nft list table inet filter

# Show rules with handles for deletion
nft -a list table inet filter

# Monitor packet matching in real-time
nft monitor

# Add counters to specific rules
nft add rule inet filter input tcp dport 22 counter

To test rule effectiveness, use tcpdump or nmap from another host:

# On firewall host
tcpdump -i eth0 -n port 22

# From remote host
nmap -p 22,80,443 firewall-host

Migration Strategy and Best Practices

Migrating from iptables to nftables starts with translation. The iptables-translate utility converts individual commands:

# Install translation tools
apt-get install iptables-nftables-compat

# Translate a single rule
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# Output: nft add rule ip filter INPUT tcp dport 22 counter accept

# Translate entire ruleset
iptables-save | iptables-restore-translate -f /etc/nftables.conf

Always backup your current configuration before changes:

# iptables backup
iptables-save > /root/iptables-backup-$(date +%F).rules

# Restore if needed
iptables-restore < /root/iptables-backup-2024-01-15.rules

# nftables backup
nft list ruleset > /root/nftables-backup-$(date +%F).conf

# Restore
nft -f /root/nftables-backup-2024-01-15.conf

Test new rulesets safely by setting a cronjob to restore the old configuration:

# Set restoration in 5 minutes
echo "nft flush ruleset; nft -f /root/working-config.conf" | at now + 5 minutes

# Apply new ruleset
nft -f /root/new-config.conf

# If it works, cancel the restoration
atrm <job-number>

Performance-wise, nftables excels with large rulesets (1000+ rules) due to better kernel data structures. For typical servers with dozens of rules, the difference is negligible. However, nftables’ atomic updates prevent the brief vulnerability window that occurs when iptables flushes and rebuilds rules.

Conclusion

Both iptables and nftables provide robust packet filtering through the netfilter framework. iptables remains the pragmatic choice for maintaining existing infrastructure and leveraging extensive documentation. nftables offers technical advantages—unified syntax, better performance, atomic updates—that make it superior for new deployments.

The Linux kernel will maintain netfilter compatibility for the foreseeable future, so there’s no urgency to migrate working iptables configurations. However, investing time in learning nftables pays dividends through simplified rule management and future-proofing your infrastructure skills.

Start experimenting with nftables in development environments. The syntax takes adjustment, but the consistency across protocol families and improved scripting capabilities justify the learning curve. For production migrations, translate incrementally, test thoroughly, and maintain backups until confidence is established.

Liked this? There's more.

Every week: one practical technique, explained simply, with code you can use immediately.