Linux · Firewall · Networking · Security

iptables
Cheatsheet

A comprehensive reference for iptables — the low-level Linux firewall tool — covering tables, chains, rules, targets, NAT, stateful packet inspection, logging, and rule persistence.

Tool: iptables
Level: Intermediate → Advanced
OS: Linux (kernel-level)
Sections: 9
Ubuntu iptables Guide

What is iptables?

iptables is the low-level Linux kernel firewall that directly controls the Netfilter packet filtering framework. Unlike UFW (a simplified frontend), iptables gives you granular, explicit control over every aspect of packet filtering, NAT, and packet mangling.

What it does: iptables inspects every network packet passing through the kernel and applies rules to accept, drop, reject, log, or redirect them. Rules are organised into tables (filter, nat, mangle) and chains (INPUT, OUTPUT, FORWARD).

Real-world use: Network security on Linux servers, building routers and firewalls, NAT/masquerading for internet sharing, port forwarding, and security hardening. Required knowledge for RHCSA, LFCS, and network security certifications. Note: modern systems may use nftables as the backend, but iptables syntax remains widely used.

Packet filtering & firewall rules
NAT & port forwarding
Traffic routing & redirection
Packet logging & monitoring

⚠️ Remote Server Warning: Misconfigured iptables rules can lock you out of a remote server. Always ensure SSH (port 22) is allowed before adding DROP policies. Consider using UFW for simpler firewall management.

3
Main Tables
5
Built-in Chains
kernel
Level
netfilter
Framework

1. Tables & Chains

iptables has three main tables, each with specific chains.

Incoming:
Network
PREROUTING
INPUT
Local Process
Outgoing:
Local Process
OUTPUT
POSTROUTING
Network
TableChainsPurpose
filterINPUT, OUTPUT, FORWARDDefault table — packet filtering (allow/drop). Used for firewall rules.
natPREROUTING, OUTPUT, POSTROUTINGNetwork Address Translation — port forwarding, masquerading.
mangleAll 5 chainsPacket modification — TTL, TOS, marks. Advanced use.
rawPREROUTING, OUTPUTConnection tracking bypass. Low-level, rarely needed.
ChainTraffic Type
INPUTPackets destined for the local system
OUTPUTPackets originating from the local system
FORWARDPackets routed through the system (not local origin/dest)
PREROUTINGPackets before routing decision (NAT table)
POSTROUTINGPackets after routing decision (NAT/masquerade)

2. Basic Commands

# List rules
sudo iptables -L                    # list all rules
sudo iptables -L -n -v              # verbose with numeric addresses
sudo iptables -L -n -v --line-numbers # show line numbers
sudo iptables -L INPUT -n -v        # specific chain
sudo iptables -t nat -L -n -v       # list NAT table

# Flush (clear) rules
sudo iptables -F                    # flush all rules (filter table)
sudo iptables -F INPUT              # flush specific chain
sudo iptables -t nat -F             # flush NAT table
sudo iptables -X                    # delete user-defined chains
sudo iptables -Z                    # zero packet/byte counters

# Set default policies
sudo iptables -P INPUT DROP         # drop all incoming by default
sudo iptables -P OUTPUT ACCEPT      # allow all outgoing by default
sudo iptables -P FORWARD DROP       # drop forwarded by default

3. Allow Rules (ACCEPT)

# Allow loopback (always required)
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A OUTPUT -o lo -j ACCEPT

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

# Allow SSH
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

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

# Allow DNS (UDP)
sudo iptables -A INPUT -p udp --dport 53 -j ACCEPT
sudo iptables -A OUTPUT -p udp --dport 53 -j ACCEPT

# Allow ICMP (ping)
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT

# Allow from specific IP
sudo iptables -A INPUT -s 203.0.113.10 -j ACCEPT

# Allow from subnet
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT

# Allow specific port from specific IP
sudo iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 3306 -j ACCEPT

4. Drop & Reject Rules

# DROP — silently discard packet
sudo iptables -A INPUT -p tcp --dport 23 -j DROP        # block Telnet
sudo iptables -A INPUT -s 198.51.100.5 -j DROP          # block IP
sudo iptables -A INPUT -s 10.0.0.0/8 -j DROP            # block subnet

# REJECT — drop and send error back to sender
sudo iptables -A INPUT -p tcp --dport 23 -j REJECT
sudo iptables -A INPUT -p tcp --dport 23 -j REJECT --reject-with tcp-reset

# Block outgoing (OUTPUT chain)
sudo iptables -A OUTPUT -p tcp --dport 25 -j DROP       # block outbound SMTP
sudo iptables -A OUTPUT -d 198.51.100.0/24 -j DROP      # block traffic to subnet

# Rate limiting (protect against brute-force)
sudo iptables -A INPUT -p tcp --dport 22 -m limit \
  --limit 5/min --limit-burst 10 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP

# Block invalid packets
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

5. Targets Reference

TargetDescription
ACCEPTAllow the packet through
DROPSilently discard packet — sender gets no response
REJECTDiscard packet and send ICMP/TCP error to sender
LOGLog packet to kernel log (syslog/journald) and continue processing
RETURNStop traversing current chain, return to calling chain
DNATDestination NAT — change destination address (port forwarding)
SNATSource NAT — change source address (outbound NAT)
MASQUERADEDynamic SNAT — for dynamic IP addresses (home routers)
REDIRECTRedirect packet to a different local port

6. NAT & Port Forwarding

# Enable IP forwarding (required for routing)
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# Persist in /etc/sysctl.conf: net.ipv4.ip_forward = 1

# MASQUERADE — share internet via eth0 (home router / VPN)
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Port forwarding — forward external port 8080 → internal 80
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 \
  -j REDIRECT --to-port 80

# Forward port to another host (DNAT)
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 \
  -j DNAT --to-destination 192.168.1.10:80
sudo iptables -A FORWARD -p tcp -d 192.168.1.10 \
  --dport 80 -j ACCEPT

# SNAT — change source IP for outbound traffic
sudo iptables -t nat -A POSTROUTING -s 192.168.1.0/24 \
  -o eth0 -j SNAT --to-source 203.0.113.10

7. Rule Management

# Append rule to end of chain (-A)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Insert rule at specific position (-I)
sudo iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT  # insert at top (pos 1)
sudo iptables -I INPUT 3 -s 10.0.0.5 -j DROP          # insert at position 3

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

# Delete rule by line number
sudo iptables -L INPUT --line-numbers   # find line number
sudo iptables -D INPUT 3                # delete line 3

# Replace rule (-R)
sudo iptables -R INPUT 2 -p tcp --dport 8080 -j ACCEPT

# Create custom chain
sudo iptables -N MY_CHAIN
sudo iptables -A INPUT -j MY_CHAIN      # jump to custom chain

# Delete custom chain
sudo iptables -F MY_CHAIN               # flush first
sudo iptables -X MY_CHAIN               # then delete

8. Logging

# LOG target — write to kernel log (non-terminating)
sudo iptables -A INPUT -p tcp --dport 22 \
  -j LOG --log-prefix "SSH-ACCESS: " --log-level 4

# Log then drop (LOG must come before DROP)
sudo iptables -A INPUT -s 198.51.100.0/24 \
  -j LOG --log-prefix "BLOCKED-IP: "
sudo iptables -A INPUT -s 198.51.100.0/24 -j DROP

# View iptables log entries
sudo dmesg | grep "BLOCKED-IP"
sudo journalctl -k | grep "SSH-ACCESS"
sudo tail -f /var/log/syslog | grep iptables

# Log levels: 0=emerg 1=alert 2=crit 3=err 4=warn 5=notice 6=info 7=debug

9. Saving & Persistence

iptables rules are not persistent by default — they are lost on reboot. Use these methods to persist them.

# Method 1: iptables-save / iptables-restore
sudo iptables-save > /etc/iptables/rules.v4          # save IPv4 rules
sudo ip6tables-save > /etc/iptables/rules.v6         # save IPv6 rules
sudo iptables-restore < /etc/iptables/rules.v4       # restore rules

# Method 2: iptables-persistent package (Debian/Ubuntu)
sudo apt install iptables-persistent
sudo netfilter-persistent save                       # save current rules
sudo netfilter-persistent reload                     # reload from saved
# Rules saved to: /etc/iptables/rules.v4 and rules.v6

# View saved rules
cat /etc/iptables/rules.v4

# Complete server ruleset example
sudo iptables -F                                     # flush all
sudo iptables -P INPUT DROP                          # default deny in
sudo iptables -P OUTPUT ACCEPT                       # default allow out
sudo iptables -P FORWARD DROP                        # default deny forward
sudo iptables -A INPUT -i lo -j ACCEPT               # allow loopback
sudo iptables -A INPUT -m conntrack \
  --ctstate ESTABLISHED,RELATED -j ACCEPT            # allow established
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT   # allow SSH
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT   # allow HTTP
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT  # allow HTTPS
sudo iptables-save > /etc/iptables/rules.v4          # persist

📚 Further Learning