Skip to content

Linux Firewall — iptables & nftables Complete Guide

DodaTech Updated 2026-06-24 8 min read

In this tutorial, you'll learn about Linux Firewall. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

iptables and nftables are Linux kernel packet filtering frameworks that control network traffic, implement NAT, and protect servers from unauthorized access at the network layer.

What You'll Learn

How to write iptables and nftables rules for packet filtering, port forwarding, connection tracking, Rate Limiting, and logging, plus a practical Migration Strategy from iptables to nftables on modern distributions.

Why Firewalls Matter

Every public-facing server is scanned by bots within minutes. A properly configured firewall is the first line of defense — it drops unwanted traffic before it reaches your services. Understanding raw packet filtering also lets you build complex NAT configurations, VPN routing, and traffic shaping rules that GUI tools cannot express. Doda Browser's cloud infrastructure uses nftables for all edge firewall rules.

Learning Path

flowchart LR
  A[Network Commands] --> B[SSH & Remote Access]
  B --> C[iptables & nftables
You are here] C --> D[Network Bonding] C --> E[Server Hardening] style C fill:#f90,color:#fff

iptables Architecture

iptables organizes rules into tables (filter, nat, mangle, raw) and chains (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING). Each packet traverses a specific path depending on its destination.

flowchart LR
  subgraph Incoming
    A[Packet In] --> B[PREROUTING]
    B --> C{Routing Decision}
  end
  C -->|Local Process| D[INPUT]
  C -->|Forward| E[FORWARD]
  D --> F[Local Process]
  F --> G[OUTPUT]
  E --> H[POSTROUTING]
  G --> H
  H --> I[Packet Out]

Default Policies and Rule Chains

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

# Flush existing rules
sudo iptables -F
sudo iptables -X

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

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

# Allow SSH
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT

# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW -j ACCEPT

# Log dropped packets
sudo iptables -A INPUT -j LOG --log-prefix "iptables-dropped: " --log-level 4

# Save rules
sudo iptables-save > /etc/iptables/rules.v4

Expected output of sudo iptables -L -v -n:

Chain INPUT (policy DROP 42 packets, 3120 bytes)
 pkts bytes target     prot opt in     out   source    destination
   42  3120 ACCEPT     all  --  lo     *     0.0.0.0/0 0.0.0.0/0
 1234 987K ACCEPT     all  --  *      *     0.0.0.0/0 0.0.0.0/0 ctstate RELATED,ESTABLISHED
   12   720 ACCEPT     tcp  --  *      *     0.0.0.0/0 0.0.0.0/0 tcp dpt:22 ctstate NEW
   56  3360 ACCEPT     tcp  --  *      *     0.0.0.0/0 0.0.0.0/0 multiport dports 80,443 ctstate NEW
    3   180 LOG        all  --  *      *     0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix "iptables-dropped: "

NAT with iptables

# Source NAT (masquerade) — share one public IP
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Destination NAT (port forwarding) — forward port 8080 to internal server
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8080 -j DNAT --to-destination 10.0.1.100:80

# Allow forwarded traffic
sudo iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

Rate Limiting

# Limit SSH to 10 new connections per minute per IP
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
    -m recent --set --name SSH
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
    -m recent --update --seconds 60 --hitcount 10 --name SSH -j DROP

# Limit ICMP echo requests
sudo iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 5/second -j ACCEPT
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP

nftables — The Modern Replacement

nftables is the successor to iptables, integrated into the kernel since 2014. It uses a single nft command with a simpler syntax, atomic rule replacement, and better performance.

Basic nftables Configuration

# Flush all rules and create a basic firewall
sudo nft flush ruleset

sudo nft add table inet filter
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; }'

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

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

# Allow SSH
sudo nft add rule inet filter input tcp dport 22 ct state new accept

# Allow HTTP/HTTPS
sudo nft add rule inet filter input tcp dport '{ 80, 443 }' ct state new accept

# Allow ICMP
sudo nft add rule inet filter input icmp type '{ echo-request, echo-reply }' limit rate 5/second accept

# Log and drop
sudo nft add rule inet filter input log prefix 'nftables-drop ' drop

nftables Configuration File

sudo tee /etc/nftables.conf << 'EOF'
#!/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 ct state new accept
        tcp dport { 80, 443 } ct state new accept
        icmp type { echo-request, echo-reply } limit rate 5/second accept
        log prefix "nftables-drop " drop
    }

    chain forward {
        type filter hook forward priority 0; policy drop;
    }

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

table inet nat {
    chain prerouting {
        type nat hook prerouting priority -100;
        tcp dport 8080 dnat to 10.0.1.100:80
    }

    chain postrouting {
        type nat hook postrouting priority 100;
        oif eth0 masquerade
    }
}
EOF

sudo systemctl enable --now nftables

nftables Sets and Maps

Sets reduce rule duplication:

# Define a set of allowed ports
sudo nft add set inet filter allowed_ports '{ type inet_service; elements = { 22, 80, 443, 8443 }; }'

# Use the set in a rule
sudo nft add rule inet filter input tcp dport @allowed_ports ct state new accept

# Add to a set dynamically
sudo nft add element inet filter allowed_ports '{ 8080 }'

Atomic Rule Replacement

Unlike iptables, nftables replaces the entire ruleset atomically — no gap where the firewall is down:

# Update the config file, then apply atomically
sudo nft -f /etc/nftables.conf

Migrating from iptables to nftables

# Convert iptables rules to nftables syntax
sudo iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# nft add rule ip filter INPUT tcp dport 22 accept

# Translate entire ruleset
sudo iptables-save > /tmp/rules.txt
sudo iptables-restore-translate -f /tmp/rules.txt > /tmp/rules.nft

# Use the iptables-nft compatibility layer
sudo update-alternatives --set iptables /usr/sbin/iptables-nft

Common Errors

1. Firewall Rules Applied Over SSH Drop Current Session

Adding a default-policy DROP on INPUT without first allowing established traffic disconnects you. Always add the conntrack rule first, or use at now + 5 minutes <<< "iptables -P INPUT ACCEPT" as a safety timer.

2. IPv6 Ignored

iptables and nftables rules for IPv4 do not apply to IPv6. Use ip6tables or add meta nfproto ipv6 matches in nftables.

3. Rules Lost After Reboot

iptables rules are ephemeral. Save with iptables-save > /etc/iptables/rules.v4 and install iptables-persistent. nftables config in /etc/nftables.conf loads automatically if the service is enabled.

4. Port Forwarding Not Working

Check three things: net.ipv4.ip_forward=1 must be set, the DNAT rule must be in the PREROUTING chain, and the FORWARD chain must allow the traffic. Enable forwarding: sudo sysctl -w net.ipv4.ip_forward=1.

5. Conflicting Rules from Docker

Docker manipulates iptables directly. If you restart the firewall, Docker networking breaks. Use nftables with the iptables-nft compat layer or configure Docker to use a dedicated bridge.

6. Rate Limiting Too Aggressive

Setting rate limits too low blocks legitimate traffic. Start with generous limits (10/second) and monitor logs before tightening.

7. Misordered Rules

iptables processes rules in order. A blanket REJECT before a specific ALLOW drops everything. List rules with iptables -L --line-numbers and insert with -I instead of -A.

Practice Questions

1. What is the difference between iptables filter and nat tables? The filter table handles packet filtering (allow/deny). The nat table modifies source or destination addresses for routing (MASQUERADE, DNAT).

2. How do you allow established SSH sessions to keep working after reloading the firewall? Add a rule matching -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT before the default DROP policy.

3. What nftables feature replaces iptables chains for grouping rules? nftables uses named chains within tables. Built-in chains have type filter hook declarations. User-defined chains can be called with goto or jump.

4. How do you make iptables rules persistent across reboots on Ubuntu? Install iptables-persistent: sudo apt install iptables-persistent && sudo netfilter-persistent save.

5. What command translates iptables rules to nftables syntax? iptables-translate for single rules, iptables-restore-translate for saved rulesets.

Challenge: Set up an nftables firewall on a dual-homed server (public IP on eth0, private LAN on eth1). Configure: (1) SSH access from anywhere, (2) web traffic to port 80/443, (3) masquerade for LAN clients, (4) port forwarding from host port 8443 to internal server 10.0.1.50:443, (5) rate-limited ICMP. Test with nft list ruleset and curl.

Do I need to learn iptables if nftables exists?

Yes — many legacy systems, scripts, and Docker still use iptables. Understanding both is necessary for production environments.

Can iptables and nftables coexist?

Not directly. Most distros provide iptables-nft as a compatibility layer that translates iptables syntax to nftables bytecode. Enable one framework, not both.

What is connection tracking (conntrack)?

The kernel tracks each network connection's state (NEW, ESTABLISHED, RELATED, INVALID). Using conntrack lets you allow return traffic without explicitly opening high ports.

How do I debug dropped packets?

Check counters: iptables -L -v -n shows packet and byte counts per rule. Use the LOG target to log drops. For nftables, nft list ruleset shows counters if counter was added to the rule.

What is the default nftables priority?

Input/forward/output hooks use priority 0 by default. NAT chains use -100 (prerouting) and 100 (postrouting). Lower numbers execute first.

What's Next

Linux Network Bonding Guide
Linux Server Hardening — CIS Benchmarks
Networking Commands Deep Dive

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-24.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro