iptables & nftables Cheatsheet

Persistence

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

Rules are not saved by default

Everything iptables adds lives in kernel memory. A reboot clears it, and a default ACCEPT policy means the host comes back with no firewall at all. Saving is a separate, distribution-specific step.

DistributionSave mechanismFile
Debian, Ubuntuiptables-persistent / netfilter-persistent/etc/iptables/rules.v4, rules.v6
Debian, Ubuntu (native nft)nftables.service/etc/nftables.conf
RHEL, Rocky, Alma, Fedoraiptables-services (optional)/etc/sysconfig/iptables, ip6tables
RHEL family (native nft)nftables.service/etc/sysconfig/nftables.conf
RHEL family (default)firewalld, own config/etc/firewalld/zones/*.xml
Arch Linuxiptables.service / nftables.service/etc/iptables/iptables.rules, /etc/nftables.conf
Ubuntu with ufwufw saves automatically/etc/ufw/*.rules
Alpine Linux/etc/init.d/iptables save/etc/iptables/rules-save
# which service actually owns the ruleset on this box
systemctl list-unit-files | grep -E 'iptables|nftables|firewalld|ufw'
systemctl is-enabled firewalld nftables iptables ufw 2>/dev/null

If firewalld or ufw is enabled, use its interface. Raw iptables rules survive until the next reload of either tool, then vanish without warning.

Debian and Ubuntu

sudo apt install iptables-persistent      # asks to save current rules on install

sudo netfilter-persistent save            # write rules.v4 and rules.v6
sudo netfilter-persistent reload          # load them again
sudo systemctl enable netfilter-persistent

# or write the files directly
sudo iptables-save  > /etc/iptables/rules.v4
sudo ip6tables-save > /etc/iptables/rules.v6

Do not forget rules.v6. A host with a tight IPv4 ruleset and an empty IPv6 one is fully open on IPv6, and most Linux distributions have IPv6 enabled with an address configured by SLAAC.

For a native nftables setup on the same family of distributions:

sudo nft list ruleset > /etc/nftables.conf
sudo systemctl enable --now nftables
sudo nft -c -f /etc/nftables.conf         # syntax check without loading

RHEL family

# only if you are deliberately not using firewalld
sudo dnf install iptables-services
sudo systemctl disable --now firewalld
sudo systemctl enable --now iptables ip6tables

sudo service iptables save                # writes /etc/sysconfig/iptables
sudo iptables-save > /etc/sysconfig/iptables

# the native nftables service instead
sudo systemctl enable --now nftables      # reads /etc/sysconfig/nftables.conf

/etc/sysconfig/nftables.conf normally just includes other files, so add your own file and reference it there rather than pasting a whole ruleset in.

TaskRHEL 7RHEL 8, 9, 10
Default front endfirewalld, iptables backendfirewalld, nftables backend
Raw iptables optioniptables-servicesiptables-services, still packaged
Native nft optionnot reallynftables.service, first-class
Backing kernel APIx_tablesnftables

The save file format

iptables-save output is a plain text file you can read, diff, and edit.

# Generated by iptables-save v1.8.10
*filter
:INPUT DROP [12:720]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [8241:1042113]
:logdrop - [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -j logdrop
-A logdrop -m limit --limit 5/min -j LOG --log-prefix "drop: "
-A logdrop -j DROP
COMMIT
LineMeaning
*filterstart of a table block
:INPUT DROP [12:720]built-in chain, its policy, and [packets:bytes]
:logdrop - [0:0]a user chain, - because it has no policy
-A ...one rule, exactly as you would type it
COMMITapply this table's block atomically
sudo iptables-save -c > with-counters.rules    # keep counters
sudo iptables-save -t nat                      # one table only
sudo iptables-restore < saved.rules            # replaces everything
sudo iptables-restore -n < extra.rules         # no flush, append instead
sudo iptables-restore -t < saved.rules         # test parse only

iptables-restore flushes and replaces by default, which is what makes it atomic. Use -n only when you genuinely want to add to the live ruleset.

Editing the file rather than the live ruleset

For anything beyond a one-line change, editing the save file and restoring it is safer and faster than a dozen -I commands, because the whole ruleset lands in one atomic operation and the file is reviewable.

sudo cp /etc/iptables/rules.v4 /root/rules.v4.bak
sudoedit /etc/iptables/rules.v4
sudo iptables-restore -t < /etc/iptables/rules.v4      # parse check first
sudo iptables-restore  < /etc/iptables/rules.v4
StepReason
Copy firstone-command rollback
-t parse checka typo mid-file otherwise leaves a half-applied ruleset
Restore, then test from another hostproves the file, not just the syntax
Commit the file to config managementthe running ruleset stops being the source of truth

Rebooting without locking yourself out

# stage the new rules, keep the old file until proven
sudo iptables-restore -t < /tmp/new.rules && sudo iptables-restore < /tmp/new.rules

# prove it with a brand new session, not the one you are typing in
ssh -o ControlMaster=no you@host 'echo reachable'

# only then persist
sudo cp /tmp/new.rules /etc/iptables/rules.v4
Safety netHow
Timed rollback( sleep 300 && sudo iptables-restore < /root/rules.v4.bak ) &
Second sessionkeeps working on ESTABLISHED even if new connections are blocked
Console accesscloud serial console or IPMI, know how to reach it before you need it
Reboot test in a windowthe only real proof that persistence works
Config managementrules rebuilt from source, not recovered from a dead host

The reboot test matters more than it sounds. Saving rules and loading them are separate services, and a ruleset that is saved but whose unit is not enabled looks perfectly fine until the machine restarts.

Firewall state at boot, the ordering trap

Rules load from a systemd unit, so there is a window between the network coming up and the firewall being applied. On a host that must never be exposed, set the policies in the save file rather than relying on rules alone, and make sure the firewall unit orders before the services it protects.

systemctl show -p After,Before nftables.service
systemctl show -p After,Before netfilter-persistent.service

# make a service wait for the firewall
sudo systemctl edit myapp.service
# [Unit]
# After=nftables.service
# Wants=nftables.service
RiskMitigation
Service listens before rules loadorder the unit After= the firewall unit
Empty IPv6 rulesetsave and enable rules.v6 or use the inet family in nftables
Two backends both loadedcheck iptables-legacy -S as well as nft list ruleset
firewalld overwrites manual rulesmanage through firewall-cmd, or disable firewalld deliberately
Cloud image resets rulesthe provider's own firewall or user-data script may also be writing