iptables — Manage the Linux Firewall with netfilter
Practical guide to iptables — controlling the Linux firewall via netfilter, with chains, tables, targets, NAT, connection tracking and persistent rules.
iptables is the classic front-end for the netfilter firewall in the Linux kernel: a single command lets you filter packets, build NAT rules or lock down open ports. You organise rules in tables (filter, nat, mangle, raw) and chains (INPUT, OUTPUT, FORWARD) that every packet traverses in order until a target such as ACCEPT, DROP or REJECT applies. On modern systems nftables is gradually replacing the tool – but iptables-nft keeps the familiar syntax alive as a compatibility layer. This guide walks you through the options you reach for daily, from listing rules to a stateful firewall with connection tracking.
Listing Rules
iptables -L — List all rules in the filter table.
sudo iptables -Liptables -L -n — List rules with numeric addresses and ports (no DNS lookups).
sudo iptables -L -niptables -L -v — List rules with packet/byte counters.
sudo iptables -L -viptables -L -n -v --line-numbers — List rules with line numbers, numeric, and verbose. Most useful format.
sudo iptables -L -n -v --line-numbersiptables -L CHAIN — List rules in a specific chain (INPUT, OUTPUT, FORWARD).
sudo iptables -L INPUT -niptables -t TABLE -L — List rules in a specific table (filter, nat, mangle, raw).
sudo iptables -t nat -L -niptables -S — List rules in iptables-save format (easier to read and re-apply).
sudo iptables -Siptables -S CHAIN — List rules for a specific chain in save format.
sudo iptables -S INPUTBasic Rule Management
iptables -A CHAIN RULE — Append a rule to the end of a chain.
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPTiptables -I CHAIN RULE — Insert a rule at the beginning of a chain.
sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPTiptables -I CHAIN NUM RULE — Insert a rule at a specific position (line number).
sudo iptables -I INPUT 3 -p tcp --dport 8080 -j ACCEPTiptables -D CHAIN RULE — Delete a rule by specification.
sudo iptables -D INPUT -p tcp --dport 80 -j ACCEPTiptables -D CHAIN NUM — Delete a rule by line number.
sudo iptables -D INPUT 3iptables -R CHAIN NUM RULE — Replace a rule at a specific line number.
sudo iptables -R INPUT 2 -p tcp --dport 8443 -j ACCEPTChain Management
iptables -P CHAIN TARGET — Set the default policy for a built-in chain (ACCEPT or DROP). Caution: -P INPUT DROP over SSH locks you out unless an ACCEPT rule for your connection already exists – add it first.
sudo iptables -P INPUT DROPiptables -F — Flush (delete) all rules in all chains. If the policy is set to DROP, a flush can lock out a remote/SSH session – ideally run it locally at the console.
sudo iptables -Fiptables -F CHAIN — Flush all rules in a specific chain.
sudo iptables -F INPUTiptables -Z — Zero all packet and byte counters.
sudo iptables -Ziptables -N CHAIN — Create a new custom chain.
sudo iptables -N MY_CHAINiptables -X CHAIN — Delete a custom chain (must be empty and unreferenced).
sudo iptables -X MY_CHAINiptables -E OLD NEW — Rename a custom chain.
sudo iptables -E MY_CHAIN NEW_CHAINMatch Criteria
-p PROTOCOL — Match by protocol: tcp, udp, icmp, all.
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT-s SOURCE/MASK — Match by source IP or network.
sudo iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT-d DEST/MASK — Match by destination IP or network.
sudo iptables -A OUTPUT -d 10.0.0.0/8 -j DROP--dport PORT — Match by destination port (requires -p tcp or -p udp).
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT--sport PORT — Match by source port.
sudo iptables -A INPUT -p tcp --sport 1024:65535 -j ACCEPT--dport PORT1:PORT2 — Match a range of destination ports.
sudo iptables -A INPUT -p tcp --dport 8000:9000 -j ACCEPT-i INTERFACE — Match incoming interface (for INPUT and FORWARD).
sudo iptables -A INPUT -i eth0 -j ACCEPT-o INTERFACE — Match outgoing interface (for OUTPUT and FORWARD).
sudo iptables -A OUTPUT -o lo -j ACCEPT! -s SOURCE — Negate a match (NOT).
sudo iptables -A INPUT ! -s 192.168.1.0/24 -j DROPTargets (Actions)
-j ACCEPT — Allow the packet.
-j DROP — Silently discard the packet (no response).
-j REJECT — Reject the packet and send an ICMP error.
-j REJECT --reject-with TYPE — Reject with a specific ICMP type: icmp-port-unreachable, tcp-reset, etc.
sudo iptables -A INPUT -p tcp --dport 23 -j REJECT --reject-with tcp-reset-j LOG — Log the packet to syslog/journal, then continue processing.
sudo iptables -A INPUT -j LOG --log-prefix 'IPT-DROP: '-j LOG --log-prefix 'PREFIX' — Log with a custom prefix for easy identification in logs.
sudo iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix 'SSH: '-j RETURN — Return from the current chain to the calling chain.
Connection Tracking (Stateful)
-m conntrack --ctstate STATE — Match by connection state: NEW, ESTABLISHED, RELATED, INVALID.
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT-m conntrack --ctstate NEW — Match new connections only.
sudo iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT-m conntrack --ctstate INVALID — Match packets that don't belong to any known connection.
sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROPExtended Modules
-m multiport --dports P1,P2,P3 — Match multiple ports in a single rule.
sudo iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT-m iprange --src-range IP1-IP2 — Match a range of source IPs.
sudo iptables -A INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -j ACCEPT-m limit --limit RATE — Rate limit matches (e.g., 5/min, 1/sec).
sudo iptables -A INPUT -p icmp -m limit --limit 1/sec -j ACCEPT-m limit --limit-burst N — Set the burst limit for rate limiting.
sudo iptables -A INPUT -p icmp -m limit --limit 1/sec --limit-burst 4 -j ACCEPT-m recent --name LIST --set — Add source IP to a named tracking list.
sudo iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --set-m recent --name LIST --rcheck --seconds S --hitcount N — Check if source IP hit N times in S seconds.
sudo iptables -A INPUT -p tcp --dport 22 -m recent --name ssh --rcheck --seconds 60 --hitcount 4 -j DROP-m comment --comment 'TEXT' — Add a comment to a rule for documentation.
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT -m comment --comment 'Allow HTTP'NAT Table
iptables -t nat -A POSTROUTING -o IFACE -j MASQUERADE — Enable NAT/masquerading for internet sharing.
sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEiptables -t nat -A PREROUTING -p tcp --dport PORT -j DNAT --to-destination IP:PORT — Port forwarding: redirect incoming traffic to another host/port.
sudo iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80iptables -t nat -A PREROUTING -p tcp --dport PORT -j REDIRECT --to-port PORT — Redirect traffic to a different local port.
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080iptables -t nat -A POSTROUTING -s NETWORK -j SNAT --to-source IP — Source NAT: change source IP for outgoing packets.
sudo iptables -t nat -A POSTROUTING -s 10.0.0.0/8 -j SNAT --to-source 203.0.113.1Save & Restore
iptables-save — Dump all current rules in a restorable format. Rules are not persistent – without this step (or netfilter-persistent) they are lost on reboot.
sudo iptables-save > /etc/iptables/rules.v4iptables-restore < FILE — Restore rules from a saved file.
sudo iptables-restore < /etc/iptables/rules.v4iptables-save -t TABLE — Save rules from a specific table only.
sudo iptables-save -t filteriptables-save -c — Save rules including packet/byte counters.
sudo iptables-save -c > rules-with-counters.v4Common Firewall Patterns
iptables -A INPUT -i lo -j ACCEPT — Allow all loopback traffic (essential).
sudo iptables -A INPUT -i lo -j ACCEPTiptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT — Allow established and related connections (stateful firewall base rule).
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTiptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT — Allow SSH, HTTP, and HTTPS.
sudo iptables -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPTiptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT — Allow ping requests.
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPTiptables -P INPUT DROP — Set default policy to DROP (deny all not explicitly allowed). Only set this after the ACCEPT rules above, otherwise you lock yourself out over SSH; then persist the rules with iptables-save.
sudo iptables -P INPUT DROP Conclusion
iptables looks daunting at first because of its sheer number of options, yet it follows a clear logic: packets traverse chains until a target decides their fate. Once you understand rule order and how connection tracking interacts with the default policy, you can build robust firewalls. Remember to persist your rules with iptables-save or netfilter-persistent – otherwise they vanish on the next reboot. And whenever possible, test a default DROP policy locally or over a second session before you lock yourself out.
Further Reading
- iptables(8) – manual page – the complete option reference
- iptables – Arch Wiki – in-depth practical guide
- iptables – Wikipedia – background and history