About the nftables cheat sheet
nftables replaces iptables and its siblings with a single framework and a consistent syntax. The structural change is that nothing exists by default — you create a table, add a chain with an explicit hook and priority, and then add rules. With iptables the chains were already there whether you used them or not.
That explicitness is an improvement and an easy way to lock yourself out. A chain declared with a drop policy starts dropping the moment it is created, before you have added the rule permitting your own SSH session. On a remote machine, that is a one-command outage.
Sets are the feature most worth adopting. Rather than one rule per address or port, a set holds many values and a single rule matches against it, which is faster at scale and far easier to maintain. Rulesets that were hundreds of near-identical iptables lines usually collapse to a handful of rules and a set.
Frequently asked questions
How do I avoid locking myself out?
Add the rule accepting your existing connection before setting a restrictive policy, and work inside a session you can afford to lose. Better, load the ruleset with a scheduled command that flushes it after a few minutes unless you cancel — if you get it wrong, access returns by itself rather than requiring console access.
Can nftables and iptables coexist?
On modern systems the iptables command is usually a translation layer writing nftables rules underneath, so they are not truly separate. Mixing native nftables rules with legacy iptables tooling is confusing rather than broken. Pick one interface and view the full ruleset natively to see everything that is actually loaded.
How do I make rules persist across reboot?
Write the ruleset to the distribution's nftables configuration file and enable its service, or save and restore it from a systemd unit. Rules added at the command line live only in memory. Keep the file in version control — a firewall that exists only on the machine is a firewall nobody can review.
What replaced the separate tables for NAT and mangle?
They are no longer fixed. You declare a table of a family and add chains with the hook and priority you need, so a single table can contain filtering and NAT chains. Priorities determine ordering relative to other hooks, which is what the old fixed table names implied implicitly.
Why are my counters not incrementing?
Either traffic is matching an earlier rule, or the chain's hook is not on the path that traffic takes. Add explicit counters and check chain priorities. Traffic between containers or through a bridge frequently traverses different hooks than expected, which is the usual explanation on a container host.