Restore IPv4 and IPv6 Firewall Rules with iptables-restore

Loading the wrong ruleset with iptables-restore can flush your existing firewall in one go. This builds a repeatable way to validate a file before you commit it, using iptables 1.8.10 on the nf_tables backend. Allow about 20 minutes, plus time to prepare a ruleset that matches your host.

You need a shell, the iptables package, a ruleset file, and an administrator account. Reading files and checking the installed version are ordinary commands; testing and restoring firewall rules need elevated privileges here. A mistake can interrupt SSH, web traffic or other services, so keep an existing console or out-of-band login available before you commit a change.

1. Check the installed command

Confirm which implementation and version will process the file. This avoids applying advice for a different binary or backend:

$ iptables-restore --version
iptables-restore v1.8.10 (nf_tables)
$ command -v iptables-restore
/usr/sbin/iptables-restore
$ command -v ip6tables-restore
/usr/sbin/ip6tables-restore

The installed manpage documents the two commands as aliases for the IPv4 and IPv6 forms of the same operation. Both accept rules on standard input or from a file argument. The package version is distribution-specific, so keep this check in your incident runbook.

2. Inspect the ruleset before touching the firewall

A restore file normally contains table sections, chain policies and rules. A small filter-table example looks like this:

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
COMMIT

The table header selects the table, the colon lines define built-in chains and their policies, and COMMIT ends the transaction for that table. In a real file, keep the rules produced by your firewall design or a trusted backup. Do not paste an example with an ACCEPT policy into a production host unless that is deliberately what you want.

Check the file as the same account that will run the restore:

$ sed -n '1,160p' /path/to/firewall.rules
$ test -r /path/to/firewall.rules && echo "ruleset is readable"
ruleset is readable

Checkpoint: identify whether the file contains IPv4 or IPv6 addresses, and whether it holds more than one table. Use iptables-restore for IPv4 syntax and ip6tables-restore for IPv6. Do not assume an IPv4 ruleset can be passed unchanged to the IPv6 command.

3. Run a parse-only test

Use --test before committing rules. It parses and constructs the ruleset without committing it, which is a safety check, not full proof the policy is correct:

$ sudo iptables-restore --test /path/to/firewall.rules
$ printf 'test exit status: %s\n' "$?"
test exit status: 0

Use the IPv6 command for an IPv6 file:

$ sudo ip6tables-restore --test /path/to/firewall-v6.rules
$ printf 'IPv6 test exit status: %s\n' "$?"
IPv6 test exit status: 0

On this installation, an unprivileged test reached the ruleset check and then failed with a root-required permission error, which is why the examples use sudo. A non-zero status means the file was not accepted by the command as run: read the diagnostic before editing the rules blindly, and test the exact file, command and table combination you plan to commit.

4. Understand the flush default

Without an option, restore flushes the previous contents of each table represented by the input, deleting the existing rules there before loading the supplied state. That is often right for replacing a complete saved ruleset, but dangerous for a partial file.

Use --noflush when you deliberately want to keep existing table contents and add or update what the input describes:

$ sudo iptables-restore --test --noflush /path/to/firewall.rules
$ printf 'non-flushing test exit status: %s\n' "$?"
non-flushing test exit status: 0

This does not make a partial ruleset safe by itself. A duplicate rule, an unexpected chain policy or a rule that depends on an existing chain can still produce a broken firewall. Decide explicitly between a complete replacement and a deliberate merge, and record that decision in the change notes.

5. Restore the tested ruleset

Warn anyone using the host, then run the same command without --test. This is the state-changing step:

$ sudo iptables-restore /path/to/firewall.rules
$ printf 'restore exit status: %s\n' "$?"
restore exit status: 0

A zero status only says the restore command completed successfully. It does not say SSH remains reachable, that a service is reachable from the intended network, or that the rules express your security policy: verify those separately, from a permitted console and an appropriate test client.

Warning: there is no generic undo flag. Recovery means restoring a known-good backup, for example:

$ sudo iptables-restore /path/to/known-good-firewall.rules
$ sudo ip6tables-restore /path/to/known-good-firewall-v6.rules

Do not run the recovery files unless you have checked they match this host. If the new rules block your only remote session, use the out-of-band console or the provider's rescue path.

6. Use the options that solve real operational problems

$ sudo iptables-restore --wait 10 /path/to/firewall.rules
$ sudo iptables-restore --test --table filter /path/to/firewall.rules

7. Check the result and record the boundary

Use the matching save command to inspect the active ruleset after a successful restore, if it is available on the host:

$ sudo iptables-save | sed -n '1,160p'
$ sudo ip6tables-save | sed -n '1,160p'

Compare the output with the intended backup, then test the services that matter. A restore changes kernel firewall state immediately; it does not automatically create a persistent file or configure boot-time loading. Persistence is a separate distribution or service-management task, and needs testing on its own.

Done means