Hierarchy
Nftables is organized as:
table (name + family: ip, ip6, inet, arp, bridge, netdev)
└── chain (type + hook + priority)
└── rule (matches + verdict)
- table: namespace for rules. The
inetfamily covers both IPv4 and IPv6. - chain: a hook point in netfilter:
prerouting(before routing)input(to us, after routing)forward(through us, not to us)output(we are the sender)postrouting(after routing, before sending)
- rule: conditions plus a verdict (
accept,drop,reject,jump,log,masquerade,dnat, ...)
Minimal firewall
Build an input filter that drops everything except SSH:
bash
sudo nft add table inet filter
sudo nft 'add chain inet filter input { type filter hook input priority 0; policy drop; }'sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input iif lo accept
sudo nft add rule inet filter input tcp dport 22 accept
sudo nft add rule inet filter input ip protocol icmp icmp type echo-request accept
What this does:
- Creates the
inet filtertable (for v4+v6) and an input chain with policy drop. - Allows established connections (without this, replies to your outgoing traffic are dropped).
- Loopback is always allowed.
- Opens SSH (port 22).
- Allows ping (echo-request).
Everything else is dropped by the default policy.
Listing and deleting
bash
sudo nft list ruleset # everything currently loaded
sudo nft list table inet filter # one table
sudo nft -a list ruleset # with handles (needed for deletion)
sudo nft delete rule inet filter input handle 5
sudo nft delete table inet filter # remove everything in the table
sudo nft flush ruleset # REMOVE EVERYTHING (dangerous - you may lose SSH access)
NAT requires a separate chain type
For nat you need a chain with type nat, not filter:
bash
sudo nft add table inet nat
sudo nft 'add chain inet nat postrouting { type nat hook postrouting priority 100; }'sudo nft add rule inet nat postrouting oifname eth0 masquerade
Persistence
Rules live in memory. To survive a reboot, save them to a file:
bash
sudo nft list ruleset > /etc/nftables.conf
sudo systemctl enable nftables # on Debian/Ubuntu
The file is then loaded by the init script.
Iptables vs nftables
- iptables: old, but still widespread (Docker, k8s until recently).
- nftables: newer, faster by design, a single CLI for all families.
- On modern Ubuntu,
iptablesis a shim: commands are translated to nft. - For migration:
iptables-restore-translateconverts old configs.