iptables and nftables Basics - Introduction to Packet Filtering

iptables and nftables Basics - Introduction to Packet Filtering

What Is the Difference Between iptables and nftables?

iptables has been the de facto Linux firewall tool for decades, but nftables is now the modern replacement. Ubuntu 22.04 and later use nftables by default (via an iptables-nft compatibility layer). The rule of thumb is: use iptables for maintaining existing servers, and nftables for new setups.

Attribute iptables nftables
Introduced 1998 2014 (Linux 3.13)
Syntax Complex, verbose Unified, concise
IPv4/IPv6 Separate (ip6tables) Unified (inet family)
Ubuntu 22.04 Via iptables-nft layer Native

On Ubuntu 22.04+, running iptables actually routes through nftables internally. Run update-alternatives --list iptables to see which implementation is active.

iptables Structure

iptables organizes rules in a three-level hierarchy: table → chain → rule. Most firewall work happens in the filter table across three chains.

The three chains in the filter table:

  • INPUT: Packets destined for this machine
  • OUTPUT: Packets originating from this machine
  • FORWARD: Packets being routed through (router setups only)

Rule targets:

  • ACCEPT: Allow the packet through
  • DROP: Silently discard (no notification to sender)
  • REJECT: Discard and send an error back

Basic iptables Commands

Always start by reviewing existing rules. Use -n to skip DNS lookups and -v for packet counters.

Viewing Rules

# List all chains with details
iptables -L -n -v

# List INPUT chain with line numbers
iptables -L INPUT -n -v --line-numbers

Adding Rules

# Allow loopback (required)
iptables -A INPUT -i lo -j ACCEPT

# Allow established connections (required)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow SSH (port 22)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP and HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Drop everything else
iptables -A INPUT -j DROP

Deleting and Resetting Rules

# Delete by line number (get numbers with --line-numbers)
iptables -D INPUT 3

# Delete by rule specification (replace -A with -D)
iptables -D INPUT -p tcp --dport 80 -j ACCEPT

# Flush all rules in all chains
iptables -F

# Reset default policies to ACCEPT
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT

If you flush rules (iptables -F) while the default policy is DROP, any open SSH session will be cut. Always verify the default policy before flushing rules on a remote server.

nftables Structure

nftables uses a four-level hierarchy: family → table → chain → rule. Unlike iptables, you must explicitly create tables and chains before adding rules. Using the inet family lets you handle both IPv4 and IPv6 in a single ruleset.

# Show the entire active ruleset
nft list ruleset

# Show all tables
nft list tables

# Show a specific table
nft list table inet filter

Basic nftables Commands

Create a table and chain first, then add rules. The type filter hook input priority 0 declaration is the standard pattern for an input filter chain.

Creating Tables and Chains

# Create a table
nft add table inet filter

# Create INPUT chain with drop policy
nft add chain inet filter input '{ type filter hook input priority 0 ; policy drop ; }'

# Create OUTPUT chain with accept policy
nft add chain inet filter output '{ type filter hook output priority 0 ; policy accept ; }'

Adding Rules

# Allow loopback
nft add rule inet filter input iif lo accept

# Allow established connections
nft add rule inet filter input ct state established,related accept

# Allow SSH
nft add rule inet filter input tcp dport 22 accept

# Allow HTTP and HTTPS (multiple ports in one rule)
nft add rule inet filter input tcp dport '{ 80, 443 }' accept

Deleting Rules

# List rules with handle numbers
nft list ruleset -a

# Delete a rule by handle number
nft delete rule inet filter input handle 5

Resetting All Rules

# Flush the entire ruleset
nft flush ruleset

# Or delete a specific table
nft delete table inet filter

Persisting Rules Across Reboots

Both iptables and nftables rules are lost on reboot by default. Persistence requires saving the configuration.

Persisting iptables (Ubuntu)

# Install iptables-persistent
apt install iptables-persistent

# Save current rules
netfilter-persistent save

# Or save manually
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

Persisting nftables (Ubuntu)

# Enable nftables service
systemctl enable nftables

# Save current ruleset to config file
nft list ruleset > /etc/nftables.conf

# Restart service to verify
systemctl restart nftables
systemctl status nftables

Basic /etc/nftables.conf template:

#!/usr/sbin/nft -f

flush ruleset

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

        iif lo accept
        ct state established,related accept
        tcp dport 22 accept
        tcp dport { 80, 443 } accept
    }

    chain output {
        type filter hook output priority 0; policy accept;
    }
}

On Ubuntu 22.04, the nftables.service is included by default. Edit /etc/nftables.conf and run systemctl restart nftables to apply changes.

Relationship with firewalld and ufw

On RHEL / CentOS / Fedora, firewalld acts as a frontend to nftables. On Ubuntu, ufw (Uncomplicated Firewall) provides a simpler interface to nftables/iptables and is recommended for everyday use.

# ufw basics (Ubuntu)
ufw status verbose
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status numbered

For day-to-day firewall management on Ubuntu, ufw is the simplest option. Use iptables or nftables directly when you need fine-grained control or are building complex filtering rules.

Next Reading