How to save iptables rules permanently

Runtime iptables rules disappear when the host reboots unless a boot-time loader restores them from disk. Saving the ruleset only after it has been tested prevents a firewall from silently returning to an empty or older policy during maintenance, restart, or recovery.

The iptables-save and ip6tables-save commands export the active IPv4 and IPv6 rules in the format that iptables-restore and ip6tables-restore can load later. On Debian and Ubuntu, the iptables-persistent package adds netfilter-persistent plugins that write those exports to /etc/iptables/rules.v4 and /etc/iptables/rules.v6.

Use this path for Debian and Ubuntu hosts that still manage firewall policy through iptables, including the nft-backed iptables backend used by current Ubuntu packages. Saving a broken runtime policy makes the broken policy durable, and loading persistent rules can replace runtime changes made after the last save.

Steps to save iptables rules permanently:

  1. Review the active IPv4 ruleset before saving it.
    $ sudo iptables-save
    # Generated by iptables-save v1.8.11 (nf_tables) on Fri Jun  5 21:52:03 2026
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A INPUT -p tcp -m tcp --dport 2222 -j ACCEPT
    COMMIT
    # Completed on Fri Jun  5 21:52:03 2026

    Do not save rules until management access has been tested from a separate session. A rule that blocks SSH or remote administration becomes the boot-time firewall after it is saved.

  2. Review the active IPv6 ruleset if the host accepts IPv6 traffic.
    $ sudo ip6tables-save
    # Generated by ip6tables-save v1.8.11 (nf_tables) on Fri Jun  5 21:52:03 2026
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A INPUT -p tcp -m tcp --dport 2222 -j ACCEPT
    COMMIT
    # Completed on Fri Jun  5 21:52:03 2026

    No output means no IPv6 tables were active in the tested environment. Do not treat an empty IPv6 rules file as protection on a host that routes or accepts IPv6 traffic.

  3. Refresh the Debian or Ubuntu package index.
    $ sudo apt update
  4. Install the persistence packages.
    $ sudo apt install iptables-persistent

    The installer may ask whether to save current IPv4 and IPv6 rules. Choose Yes only when the runtime rules have already been reviewed; the explicit save command writes the final files again.

  5. Confirm the persistence command is available.
    $ sudo netfilter-persistent --help
    Usage: /usr/sbin/netfilter-persistent (start|stop|restart|reload|flush|save)
  6. Save the active rules to the persistent files.
    $ sudo netfilter-persistent save
    run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables save
    run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables save
  7. Check the saved rules files.
    $ sudo ls -l /etc/iptables/rules.v4 /etc/iptables/rules.v6
    -rw-r----- 1 root root 241 Jun  5 21:52 /etc/iptables/rules.v4
    -rw-r----- 1 root root 242 Jun  5 21:52 /etc/iptables/rules.v6

    /etc/iptables/rules.v4 stores IPv4 rules, and /etc/iptables/rules.v6 stores IPv6 rules. A zero-byte file means that side had no rules to save in the tested environment.

  8. Test the saved IPv4 file without applying it.
    $ sudo iptables-restore --test /etc/iptables/rules.v4

    No output means the saved IPv4 file parsed successfully.

  9. Test the saved IPv6 file when it contains IPv6 rules.
    $ sudo ip6tables-restore --test /etc/iptables/rules.v6

    No output means the saved IPv6 file parsed successfully.

  10. Ensure the boot restore service is enabled.
    $ sudo systemctl enable netfilter-persistent

    The netfilter-persistent systemd unit runs /usr/sbin/netfilter-persistent start before the network is brought up.

  11. Load the saved files once to follow the same path used at boot.
    $ sudo netfilter-persistent start
    run-parts: executing /usr/share/netfilter-persistent/plugins.d/15-ip4tables start
    run-parts: executing /usr/share/netfilter-persistent/plugins.d/25-ip6tables start

    This applies the saved files to the running firewall. Run it only after confirming the saved files contain the rules that should be active.

  12. Confirm the expected IPv4 rule is present after the load.
    $ sudo iptables -S INPUT
    -P INPUT ACCEPT
    -A INPUT -p tcp -m tcp --dport 2222 -j ACCEPT
  13. Confirm the expected IPv6 rule is present after the load.
    $ sudo ip6tables -S INPUT
    -P INPUT ACCEPT
    -A INPUT -p tcp -m tcp --dport 2222 -j ACCEPT