iptables & nftables Cheatsheet

Listing and Counters

Use this iptables & nftables reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Reading the current ruleset

sudo iptables -L                 # human format, resolves names, slow
sudo iptables -L -n              # numeric, always prefer this
sudo iptables -L -n -v           # add packet and byte counters
sudo iptables -L -n -v --line-numbers
sudo iptables -S                 # save format, exactly what you would type back
sudo iptables -S INPUT           # one chain only
sudo iptables -t nat -L -n -v
sudo iptables-save               # every table, the canonical dump
FlagEffect
-Llist rules in a readable table
-Slist rules as -A commands, copy-pasteable
-nno DNS or service-name lookups
-vverbose, adds counters, interfaces, and options
-xexact counter values instead of 1234K
--line-numbersnumber rules, needed for -I and -D by index
-Zzero the counters

Use -S when you want to edit or reproduce rules, and -L -n -v when you want to understand what traffic is actually hitting them. -L without -n will hang on a box with broken DNS, which is a classic mid-incident time sink.

Anatomy of the -L output

Chain INPUT (policy DROP 12 packets, 720 bytes)
num   pkts bytes target     prot opt in     out     source          destination
1    18492 2.1M  ACCEPT     all  --  lo     *       0.0.0.0/0       0.0.0.0/0
2    91203  14M  ACCEPT     all  --  *      *       0.0.0.0/0       0.0.0.0/0    ctstate RELATED,ESTABLISHED
3       42  2520 ACCEPT     tcp  --  *      *       0.0.0.0/0       0.0.0.0/0    tcp dpt:22
4        7   420 REJECT     all  --  *      *       0.0.0.0/0       0.0.0.0/0    reject-with icmp-port-unreachable
ColumnMeaning
numrule position, what -D INPUT 3 refers to
pkts / bytesmatches since the counters were last zeroed
targetwhat happens on a match
protprotocol, all when unrestricted
optrule options, f marks fragment-only rules
in / outinterface constraints, * is any
source / destinationaddress matches, 0.0.0.0/0 is any
trailing textthe match extensions, such as ctstate or dpt:22

The policy line also carries counters. policy DROP 12 packets means twelve packets fell off the end of the chain and were dropped by the policy rather than by any rule, which is exactly what you want to watch after tightening a ruleset.

Counters as a debugging tool

Counters answer the only question that matters when a rule "does not work": is traffic reaching this rule at all.

sudo iptables -Z                          # zero all counters in filter
sudo iptables -Z INPUT                    # one chain
sudo iptables -Z INPUT 3                  # one rule
# ... reproduce the problem ...
sudo iptables -L INPUT -n -v --line-numbers
ObservationConclusion
Counter stays at zerothe packet never matches, check protocol, port, interface, direction
Counter rises on an earlier rulesomething above it is accepting or dropping first
Counter rises on your rule, traffic still failsthe problem is elsewhere, such as routing, NAT, or the service not listening
Policy counter risesno rule matched, the default deny caught it
# watch a single rule live
watch -n1 'sudo iptables -L INPUT -n -v --line-numbers | sed -n "1,8p"'

# exact byte counts, no K/M rounding
sudo iptables -L -n -v -x

Editing rules by position

sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT     # append to the end
sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT     # insert at position 1
sudo iptables -I INPUT 3 -p tcp --dport 80 -j ACCEPT   # insert at position 3
sudo iptables -R INPUT 3 -p tcp --dport 8080 -j ACCEPT # replace rule 3
sudo iptables -D INPUT 3                               # delete by number
sudo iptables -D INPUT -p tcp --dport 80 -j ACCEPT     # delete by exact match
sudo iptables -C INPUT -p tcp --dport 80 -j ACCEPT     # check, exit 0 if present

Order is the whole game. -A puts the rule after any catch-all deny already at the bottom of the chain, where it will never match, so a rule that "does nothing" is very often an -A that should have been an -I.

Deleting by number is convenient and dangerous: the numbers shift after every delete. Delete from the highest number down, or delete by exact match, or use -C first to confirm you are naming the rule you think you are.

Chains, flushing, and starting over

sudo iptables -N sshguard            # create a user chain
sudo iptables -E sshguard ssh-in     # rename it
sudo iptables -F INPUT               # flush one chain, keep the policy
sudo iptables -F                     # flush every chain in filter
sudo iptables -X sshguard            # delete an empty user chain
sudo iptables -X                     # delete all empty user chains
sudo iptables -P INPUT ACCEPT        # reset a policy

The safe full reset, in the order that cannot lock you out:

sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -t nat -F
sudo iptables -t mangle -F
sudo iptables -F
sudo iptables -X

Policies go back to ACCEPT first. Flushing a chain whose policy is DROP removes the rule that was letting your SSH session through and leaves the deny policy in place, which drops you immediately.

Comments, diffing, and backups

# label rules so the next person knows why they exist
sudo iptables -A INPUT -p tcp --dport 9100 -m comment \
  --comment "prometheus node_exporter, monitoring vlan only" -j ACCEPT

# snapshot before touching anything
sudo iptables-save > /root/fw-$(date +%F-%H%M).rules

# see what a change did
sudo iptables-save > /tmp/after.rules
diff -u /root/fw-2026-09-15-1030.rules /tmp/after.rules

# roll back
sudo iptables-restore < /root/fw-2026-09-15-1030.rules
HabitWhy it pays
-m comment --comment on every non-obvious rulerules outlive the ticket that created them
iptables-save before every edit sessiona one-line rollback beats reconstructing from memory
diff two savesshows the real change, including counter-free rule order
Test with -C before -Dproves the rule you are about to delete is the one you mean