iptables vs nftables on a VPS: Which to Run and How to Migrate

iptables and nftables are not two competing firewalls so much as two generations of the same one. If you still write rules with the classic iptables commands, there is a good chance they are being executed through a translation layer on top of nftables without you knowing it. Before you tune either, make sure the underlying host is worth the effort: compare managed and unmanaged plans on our VPS comparison table, because no firewall setting can compensate for an oversold or rate-limited server.

Why nftables Is the Default on Modern Distros

nftables has been in the kernel since 3.13 (2014), and every major distribution now ships it as the firewall backend. On Debian 10+, Ubuntu 18.04+, and recent RHEL releases, the iptables binary you type at the shell is almost certainly iptables-nft — a compatibility shim that translates legacy syntax into nftables netlink calls. You can confirm this in seconds:

# On any modern distro this prints "(nf_tables)"
iptables --version

# And nftables itself is present
nft --version

That has two practical consequences. First, legacy iptables rules still work, so there is no emergency migration pressure. Second, mixing both tools on one host is asking for confusion: the iptables shim and native nft manage the same kernel ruleset but expose different views of it, and rules you add with one can silently surprise you when you inspect with the other. Pick one interface and standardize on it.

What Actually Differs Under the Hood

Aspectiptables (legacy)nftables
Rule storageFour hardcoded tables (filter, nat, mangle, raw)Named tables and chains, your own structure
Atomic updatesPer-rule append/insert; full reload via iptables-restorenft -f applies an entire ruleset atomically
Complex matchesRepeated -m modules, verbose flagsSets, maps, and concatenations in one rule
Rule count performanceLinear walk per packetSet/hash lookups scale better with many rules
Toolingiptables, ip6tables, arptables, ebtablesOne nft binary, plus the compat shims

The differences that matter on a small VPS are atomic reloads and sets. Atomic reloads mean you can stage a full ruleset and swap it in without a window where a rule is missing mid-apply — exactly what you want when you are firewalling the port you are SSH’d into. Sets let you express “allow these 20 ports” as one rule instead of twenty.

Same Policy, Both Syntaxes

A typical single-VPS policy is: allow loopback, established traffic, SSH, and HTTP/S; drop everything else. In classic iptables that looks like:

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -P INPUT DROP

The same policy in native nftables fits in one file:

table inet filter {
  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    iif "lo" accept
    tcp dport { 22, 80, 443 } accept
  }
}

Load it with nft -f /etc/nftables.conf and enable the service so it survives reboots: systemctl enable --now nftables. Note the inet family — one table covers both IPv4 and IPv6, which the legacy syntax never did without a second set of ip6tables rules.

Migrating Without Locking Yourself Out

If you have an existing iptables ruleset, let the tooling do the translation instead of hand-converting every line:

# Dump current rules
iptables-save > /tmp/rules.v4

# Translate to nft syntax
iptables-restore-translate -f /tmp/rules.v4 > /tmp/rules.nft

# Review, then test-apply without touching the live ruleset
nft -c -f /tmp/rules.nft

The -c flag performs a dry run: it parses and validates the file without loading it. Review the generated rules.nft — the translator is mechanical, so comments and some compound matches will need manual cleanup. Then apply in a way that lets you bail out: keep your current SSH session open, load the new ruleset, and only close the session after confirming from a second terminal that ssh still connects and nft list ruleset shows what you expect.

Verifying the Firewall Is Actually Doing Something

  • nft list ruleset — shows every rule, table, and chain currently loaded; the single source of truth.
  • systemctl status nftables — confirms the service is active and the config file parsed cleanly at boot.
  • nft -c -f /etc/nftables.conf — re-validates the file after every edit, before you reload it.
  • Port scans from outside (or a second server) — confirm that closed ports actually drop instead of answering with RST.

One habit worth stealing from production teams: commit your nftables.conf to version control, and always test the new file with nft -c before a reload. On a box you administer over SSH, a broken firewall rule is one reboot away from a support ticket.

For most VPS workloads, the pragmatic answer is: keep whatever the distro default is, but manage it through nft so you get atomic reloads and a single syntax to learn. If you are choosing a new host and want one where the control panel does not fight your host firewall, our feature comparison lists which providers expose raw firewall access. And if your current box is too small to hold both your app and your ruleset comfortably, browse the ranked VPS provider list for plans with more headroom.

Leave a Reply