Translate iptables Rules to nftables Without Applying Them

Before you migrate a firewall from iptables to nftables, iptables-translate lets you preview every rule change on paper first. You will turn an iptables command or a saved ruleset into native nftables syntax, inspect the result, and keep the live firewall untouched until you have actually reviewed it. The installed tools here are from iptables 1.8.10-3ubuntu2 and use the nf_tables backend.

Safety boundary: these commands are text converters. They do not change the kernel firewall. The later nft -f command does change live state, so do not run it until the generated file has been reviewed and you have a recovery plan sitting ready.

1. Check which translator is installed

xtables-translate describes the family, but the installed commands expose the input dialect directly. Use iptables-translate for IPv4 commands, ip6tables-translate for IPv6 commands, and the matching restore command for a saved ruleset:

$ command -v iptables-translate ip6tables-translate iptables-restore-translate
/usr/sbin/iptables-translate
/usr/sbin/ip6tables-translate
/usr/sbin/iptables-restore-translate
$ iptables-translate --version
iptables-translate v1.8.10 (nf_tables)
$ dpkg-query -W -f='${Package} ${Version}\n' iptables
iptables 1.8.10-3ubuntu2

Checkpoint: the version output should name the command you will actually use. Formatting can shift between versions, so treat the output above as an example from this machine, not a fixed promise.

2. Translate one IPv4 command

Pass the old iptables arguments straight after the translator name. This example describes a new TCP connection to port 22 being accepted on the IPv4 input chain:

$ iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
nft 'add rule ip filter INPUT tcp dport 22 ct state new counter accept'

The result is an nft command shown as text; the translator never executes it. The ip filter table tells you this is IPv4. An IPv6 translation uses ip6 instead.

Read the output before copying it into a ruleset. Check for the expected family, table, chain, match conditions and verdict. A successful translation is not proof the rule expresses the security policy you actually intended.

3. Translate an IPv6 command separately

Use the IPv6 command for IPv6 syntax. Swap in real interface names from your host; the names below are placeholders only:

$ ip6tables-translate -A FORWARD -i eth0 -o eth3 -p udp -m multiport --dports 111,222 -j ACCEPT
nft 'add rule ip6 filter FORWARD iifname "eth0" oifname "eth3" meta l4proto udp udp dport { 111, 222 } counter accept'

Do not assume translating the IPv4 rules also covers IPv6. Translate and review both families, then check whether your host also runs bridge rules through ebtables; the installed package ships ebtables-translate for that dialect too.

Checkpoint: keep the generated output in a review file if you need to compare it against the original policy later. No privileged command is required just to produce this text.

4. Export a complete ruleset first

For a real migration, start from a saved ruleset rather than retyping individual commands. Save the IPv4 rules with iptables-save; reading firewall state may need sudo:

$ sudo iptables-save > /path/to/iptables-save.txt
$ sed -n '1,80p' /path/to/iptables-save.txt

Saving is read-only, but the file can contain addresses, interface names and other operational detail, so protect it like configuration data. For IPv6, use ip6tables-save and keep that output in a separate file.

If you cannot read the live firewall yourself, get a trusted export from its owner instead. Do not invent missing chains or policies just to make a partial file look complete.

5. Convert the saved file to nftables syntax

Use iptables-restore-translate with -f and redirect the output to a new file:

$ iptables-restore-translate -f /path/to/iptables-save.txt > /path/to/ruleset.nft
$ sed -n '1,80p' /path/to/ruleset.nft
# Translated by iptables-restore-translate v1.8.10 on ...
add table ip filter
add chain ip filter INPUT { type filter hook input priority 0; policy accept; }
add chain ip filter FORWARD { type filter hook forward priority 0; policy accept; }
add chain ip filter OUTPUT { type filter hook output priority 0; policy accept; }
add rule ip filter FORWARD tcp dport 22 ct state new counter accept

For an IPv6 export, use ip6tables-restore-translate; its output should use ip6 table declarations. The restore translators understand the syntax that iptables-save and ip6tables-save emit; they are not general-purpose converters for arbitrary firewall text someone hands you.

Review the whole file, not just its rules. Check default policies, custom chains, comments, counters, NAT behaviour, and every rule flagged with an unsupported or partially supported extension. The man page calls out unsupported extensions as a known limitation, so stop and investigate rather than let a match quietly vanish.

6. Validate the generated file without changing the live firewall

Inspect the file as text first, and keep the original export sitting beside it. You can ask nft to parse a file without applying it, using check mode:

$ nft -c -f /path/to/ruleset.nft

A successful check normally produces no output and returns status 0. Confirm that explicitly:

$ nft -c -f /path/to/ruleset.nft
$ printf 'nft check status: %s\n' "$?"
nft check status: 0

Depending on the nftables build and host permissions, the check may still need access to netfilter state. If it reports cache initialization failed: Operation not permitted, repeat the read-only check with the minimum privilege required, for example sudo nft -c -f /path/to/ruleset.nft. That grants access for validation only; it does not apply the file.

This checks nft syntax and some semantic detail. It does not prove the policy is safe, that every old extension has an equivalent, or that another service will not replace the rules later. Test in an isolated host or maintenance window before you touch a production firewall migration.

7. Apply only after a recovery plan

Warning: applying a ruleset can interrupt SSH, traffic forwarding and services. A mistake here can lock you out. Make sure you have console or out-of-band access, a known-good original export, and a tested way back to the previous firewall before running:

$ sudo nft -f /path/to/ruleset.nft
$ sudo nft list ruleset

The first command changes live state and needs elevated privileges; the second reads it back so you can compare active tables and chains against the reviewed file. If the result is wrong, use your platform's documented rollback procedure and the original firewall export. Never improvise a flush over a remote session: sudo nft flush ruleset removes the active nftables rules and can cut off access immediately.

Common traps

Done means