You have a saved iptables ruleset and need a native nftables ruleset for the same host. What does `iptables-translate` give you, and what does it not do?
answer
- converters that print, never apply
- one command in, one nft command out
- restore-translate handles a whole dump
- structure survives, idiom does not
- sets and cleanup stay manual
basics
~20 siptables-translate prints the nft command equivalent to an iptables command line and applies nothing; iptables-restore-translate -f converts a whole saved dump. Both are mechanical transliterations — you get a first draft to restructure, not an idiomatic nftables ruleset.
solid answer
~50 sYou pass `iptables-translate` the same arguments you would give `iptables`, and it prints the matching `nft` command on stdout — `iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT` yields `nft add rule ip filter INPUT tcp dport 22 counter accept`. For a whole ruleset, `iptables-restore-translate -f rules.v4` takes an `iptables-save` dump and emits an nft ruleset file. Neither one touches the kernel; they are converters, so the workflow is translate, review, then validate with `nft -c -f`. What you must not expect is idiomatic output. The translation is per-rule and structure-preserving: an `ip`-family table carrying the old INPUT/FORWARD/OUTPUT chain names, `counter` on every rule because iptables always counted, and a separate parallel job for the IPv6 side — it will not give you one `inet` table. It will not fold repeated address matches into named sets, will not spot dead or redundant rules, and a small number of matches and targets have no nft equivalent, which it tells you rather than guessing.
code
bash · 11 lines# single rule
iptables-translate -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
# whole ruleset, both families, nothing applied
iptables-save > /root/rules.v4
ip6tables-save > /root/rules.v6
iptables-restore-translate -f /root/rules.v4 > /root/ruleset-v4.nft
ip6tables-restore-translate -f /root/rules.v6 > /root/ruleset-v6.nft
# review, merge into one inet table, then validate before loading
nft -c -f /root/ruleset-v4.nftgo deeper
Know that a translation tool exists, that you invoke it exactly like the iptables command it mirrors, and that it prints the nft equivalent rather than changing anything.
Distinguish the per-command tool from the whole-dump one, and explain why the output keeps the old table and chain names and puts a counter on every rule.
Run the migration as a review: translate, delete dead rules, merge the two families into one inet table, introduce sets, validate with nft -c -f, and apply atomically with a rollback armed.
Sequence the migration across a fleet — which hosts convert first, how translated rulesets enter version control and configuration management, and what proves equivalence before the legacy ruleset is retired.
## What the translation tools are The iptables package ships translation utilities alongside the nft-backed commands: - **`iptables-translate`** / **`ip6tables-translate`** — take one iptables-style command line and print the equivalent `nft` command. - **`iptables-restore-translate`** / **`ip6tables-restore-translate`** — take an `iptables-save`-format dump with `-f` and print a whole nftables ruleset file. None of them changes the running configuration. They are pure converters that write to stdout, which is the right design: migration is a review exercise, not a button. ```bash $ 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 whole-ruleset path ```bash iptables-save > /root/rules.v4 iptables-restore-translate -f /root/rules.v4 > /root/ruleset.nft nft -c -f /root/ruleset.nft ``` That gives you a file you can read, diff and put in version control before anything is applied. Do the same with `ip6tables-save` and `ip6tables-restore-translate` for the IPv6 half. ## What the output actually looks like This is where expectations need managing. The translation is faithful to the input, which means it is faithful to the input's *structure*: - **Family.** IPv4 rules become an `ip`-family table and IPv6 rules an `ip6`-family table. You get two rulesets, exactly as before. Converting them into a single `inet` table — the main thing you moved for — is manual work. - **Chain names and layout.** The legacy `filter`/`nat`/`mangle` table names and the uppercase INPUT/FORWARD/OUTPUT chain names come straight across, complete with the built-in-chain shape. In nftables those are just names you happen to have chosen; nothing requires them. - **`counter` everywhere.** iptables counted every rule unconditionally, so the translator inserts `counter` to preserve behaviour. In a native ruleset you would keep counters where you actually read them and drop them elsewhere. - **Rule-for-rule fidelity.** Two hundred rules in, two hundred rules out. ## What it will not do for you 1. **No sets.** Fifty rules each matching one source address translate to fifty rules matching one source address. Collapsing them into a named set — the single largest win of moving to nftables — is a decision it cannot make for you, because it cannot know whether those rules are truly interchangeable. Simple cases like `-m multiport --dports 22,80,443` do become an inline set, since the mapping there is unambiguous. 2. **No consolidation or cleanup.** Dead rules, rules shadowed by an earlier match, and rules for services decommissioned two years ago all survive the trip. Migration is the natural moment to delete them, and only a human can. 3. **No unsupported matches invented.** A handful of matches and targets have no nftables equivalent. The tool reports that instead of emitting something plausible — which is the behaviour you want, because a silently wrong firewall rule is worse than a loud failure. 4. **Nothing applied.** It prints. Loading is a separate, deliberate `nft -f`. ## A workable migration sequence 1. Save both rulesets (`iptables-save`, `ip6tables-save`) and keep the originals. 2. Translate both to nft files and read them end to end. 3. Delete what is dead. This is usually a surprising fraction of the ruleset. 4. Merge the v4 and v6 files into one `inet` table, keeping family-specific matches where the rule really is protocol-specific and remembering that ICMPv6 must be handled explicitly. 5. Fold repeated address and port matches into named sets, and consider a verdict map for a long per-port dispatch. 6. Add `flush ruleset` (or a scoped table delete) at the top, and validate with `nft -c -f`. 7. Apply with `nft -f` in one transaction, with a rollback armed if the host is remote, then confirm with `nft list ruleset`. ## The honest summary The translator's value is that it removes the tedious and error-prone part — remembering that `--ctstate` becomes `ct state`, that `-i` becomes `iif`, that `-j MASQUERADE` becomes `masquerade` — and gives you a mechanically correct starting point. The value you add is structure: one dual-stack table, sets instead of rule lists, and a ruleset that is shorter than the one you started with.
- After translating, what is the first structural change you would make to the output by hand?Merge the `ip` and `ip6` tables into a single `inet` table, since maintaining one dual-stack ruleset is the main reason to migrate. Keep `ip`/`ip6` matches only where the rule is genuinely protocol-specific, and handle ICMPv6 explicitly — a translated v4 chain that allowed `icmp` gives no cover for Neighbour Discovery once the chain also sees IPv6.
- The translator emits `counter` on nearly every rule. Should you keep them?Only where you read them. iptables counted unconditionally, so the translator preserves that to keep behaviour identical, but counters cost a little per packet and clutter `nft list ruleset`. Keep them on the rules you actually inspect during an incident — drops, catch-alls, anything you graph — and drop them from the routine accepts.
- How do you verify the translated ruleset behaves like the original before trusting it?`nft -c -f` proves only that it parses and is supported. Real confidence comes from exercising it: apply it on a staging host, drive the traffic patterns you care about, and compare counters on the catch-all rules against the old ruleset's. On the production host, apply in one transaction with a timed rollback and confirm your own access first.
saying these in an interview costs you the question
- Thinks iptables-translate applies the converted rules
- Expects a single idiomatic inet table from the output
- Assumes repeated address rules become named sets
- Believes translation removes redundant or dead rules
- Forgets the IPv6 ruleset needs its own translation pass