nftables — The Modern Linux Firewall with nft
Practical guide to nftables — the modern iptables successor. Tables, chains, rules, sets and NAT with the nft syntax, plus hardened firewall setups.
nftables is the unified firewall of the Linux kernel, replacing the legacy tools iptables, ip6tables, arptables, and ebtables under a single command: nft. Instead of four separate toolsets, you manage IPv4, IPv6, ARP, and bridge traffic with one consistent syntax of tables, chains, rules, sets, and maps. Rule changes are applied atomically, and named sets keep large address lists fast and maintainable. This guide takes you from listing existing rules through match expressions and NAT to a complete, hardened firewall setup.
Listing Rules
nft list ruleset — List all rules across all tables and families.
sudo nft list rulesetnft list tables — List all tables.
sudo nft list tablesnft list table FAMILY TABLE — List all chains and rules in a specific table.
sudo nft list table inet filternft list chain FAMILY TABLE CHAIN — List rules in a specific chain.
sudo nft list chain inet filter inputnft -a list ruleset — List all rules with handle numbers (needed for deleting).
sudo nft -a list rulesetnft -s list ruleset — List rules without string translation (numeric protocols/ports).
sudo nft -s list rulesetnft -j list ruleset — List rules in JSON format.
sudo nft -j list rulesetAddress Families
ip — IPv4 only (equivalent to iptables).
ip6 — IPv6 only (equivalent to ip6tables).
inet — Both IPv4 and IPv6 in one table. Recommended for most use cases.
arp — ARP protocol (equivalent to arptables).
bridge — Bridge/layer 2 filtering (equivalent to ebtables).
netdev — Ingress filtering at the device level (before routing).
Table Management
nft add table FAMILY NAME — Create a new table.
sudo nft add table inet filternft delete table FAMILY NAME — Delete a table and all its chains/rules.
sudo nft delete table inet filternft flush table FAMILY NAME — Remove all rules from a table (keep chains).
sudo nft flush table inet filternft flush ruleset — Remove all tables, chains, and rules. Caution: with remote access and a default policy drop, this locks you out — allow SSH/established first and test locally only.
sudo nft flush rulesetChain Management
nft add chain FAMILY TABLE CHAIN '{ type TYPE hook HOOK priority PRIO; policy POLICY; }' — Create a base chain with hook, priority, and policy. Be careful with policy drop before adding accept rules (e.g. for SSH/established) – see the hardened setup below.
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'nft add chain FAMILY TABLE CHAIN — Create a regular (non-base) chain for organizing rules.
sudo nft add chain inet filter tcp_chainnft delete chain FAMILY TABLE CHAIN — Delete a chain (must be empty).
sudo nft delete chain inet filter tcp_chainnft flush chain FAMILY TABLE CHAIN — Remove all rules from a chain.
sudo nft flush chain inet filter inputAdding Rules
nft add rule FAMILY TABLE CHAIN STATEMENT — Append a rule to the end of a chain.
sudo nft add rule inet filter input tcp dport 80 acceptnft insert rule FAMILY TABLE CHAIN STATEMENT — Insert a rule at the beginning of a chain.
sudo nft insert rule inet filter input tcp dport 443 acceptnft add rule FAMILY TABLE CHAIN position HANDLE STATEMENT — Add a rule after a specific handle.
sudo nft add rule inet filter input position 8 tcp dport 8080 acceptnft insert rule FAMILY TABLE CHAIN position HANDLE STATEMENT — Insert a rule before a specific handle.
sudo nft insert rule inet filter input position 8 tcp dport 22 acceptDeleting Rules
nft delete rule FAMILY TABLE CHAIN handle HANDLE — Delete a rule by handle number (use -a to find handles).
sudo nft delete rule inet filter input handle 12nft flush chain FAMILY TABLE CHAIN — Delete all rules in a chain.
sudo nft flush chain inet filter inputMatch Expressions
tcp dport PORT — Match TCP destination port.
sudo nft add rule inet filter input tcp dport 22 acceptudp dport PORT — Match UDP destination port.
sudo nft add rule inet filter input udp dport 53 accepttcp dport { P1, P2, P3 } — Match multiple ports using anonymous sets.
sudo nft add rule inet filter input tcp dport { 80, 443, 8080 } accepttcp dport P1-P2 — Match a port range.
sudo nft add rule inet filter input tcp dport 8000-9000 acceptip saddr ADDRESS — Match source IPv4 address.
sudo nft add rule inet filter input ip saddr 192.168.1.0/24 acceptip daddr ADDRESS — Match destination IPv4 address.
sudo nft add rule inet filter output ip daddr 10.0.0.0/8 dropip6 saddr ADDRESS — Match source IPv6 address.
sudo nft add rule inet filter input ip6 saddr fd00::/8 acceptip saddr { A1, A2, A3 } — Match multiple source addresses.
sudo nft add rule inet filter input ip saddr { 10.0.0.1, 10.0.0.2 } acceptiifname INTERFACE — Match incoming interface name.
sudo nft add rule inet filter input iifname "eth0" acceptoifname INTERFACE — Match outgoing interface name.
sudo nft add rule inet filter output oifname "lo" acceptmeta l4proto icmp — Match ICMP protocol.
sudo nft add rule inet filter input meta l4proto icmp acceptct state { established, related } — Match connection tracking state.
sudo nft add rule inet filter input ct state { established, related } acceptct state invalid — Match invalid connection state.
sudo nft add rule inet filter input ct state invalid dropct state new — Match new connections.
sudo nft add rule inet filter input ct state new tcp dport 22 acceptActions (Verdicts)
accept — Allow the packet.
drop — Silently discard the packet.
reject — Reject the packet with an ICMP error.
reject with TYPE — Reject with a specific message type.
sudo nft add rule inet filter input tcp dport 23 reject with tcp resetlog prefix "TEXT" — Log the packet with a prefix.
sudo nft add rule inet filter input tcp dport 22 log prefix "SSH: " acceptcounter — Count packets and bytes matching this rule.
sudo nft add rule inet filter input tcp dport 80 counter acceptjump CHAIN — Jump to another chain for further processing.
sudo nft add rule inet filter input tcp dport { 80, 443 } jump web_chainreturn — Return from the current chain.
limit rate N/TIME — Rate limit matches (e.g., 5/minute, 1/second).
sudo nft add rule inet filter input icmp type echo-request limit rate 1/second acceptNAT
nft add chain ip nat postrouting '{ type nat hook postrouting priority 100; }' — Create a NAT postrouting chain.
sudo nft add chain ip nat postrouting '{ type nat hook postrouting priority 100; }'masquerade — Masquerade outgoing traffic (dynamic SNAT).
sudo nft add rule ip nat postrouting oifname "eth0" masqueradednat to ADDRESS:PORT — Destination NAT (port forwarding).
sudo nft add rule ip nat prerouting tcp dport 8080 dnat to 192.168.1.100:80snat to ADDRESS — Source NAT with a static IP.
sudo nft add rule ip nat postrouting ip saddr 10.0.0.0/8 snat to 203.0.113.1redirect to :PORT — Redirect to a local port.
sudo nft add rule ip nat prerouting tcp dport 80 redirect to :8080Named Sets
nft add set FAMILY TABLE NAME '{ type TYPE; }' — Create a named set.
sudo nft add set inet filter blocked_ips '{ type ipv4_addr; }'nft add element FAMILY TABLE SET '{ ELEM1, ELEM2 }' — Add elements to a set.
sudo nft add element inet filter blocked_ips '{ 10.0.0.1, 10.0.0.2 }'nft delete element FAMILY TABLE SET '{ ELEM }' — Remove an element from a set.
sudo nft delete element inet filter blocked_ips '{ 10.0.0.1 }'nft list set FAMILY TABLE SET — Show contents of a named set.
sudo nft list set inet filter blocked_ipsip saddr @SET_NAME drop — Use a named set in a rule.
sudo nft add rule inet filter input ip saddr @blocked_ips dropSave & Restore
nft list ruleset > FILE — Save the current ruleset to a file. Without /etc/nftables.conf plus the enabled nftables service, rules are not persistent and are lost on reboot.
sudo nft list ruleset > /etc/nftables.confnft -f FILE — Load rules from a file.
sudo nft -f /etc/nftables.confnft -c -f FILE — Check/validate a ruleset file without applying it.
sudo nft -c -f /etc/nftables.confCommon Firewall Setup
nft add table inet filter — Step 1: Create a filter table for IPv4 and IPv6.
sudo nft add table inet filternft add chain inet filter input '{ type filter hook input priority 0; policy drop; }' — Step 2: Create input chain with drop policy. Caution: from now on everything without a matching rule is dropped — add the SSH/established rules (steps 4 and 6) first, or you will lock yourself out over remote access.
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy drop; }'nft add rule inet filter input iifname "lo" accept — Step 3: Allow loopback traffic.
sudo nft add rule inet filter input iifname "lo" acceptnft add rule inet filter input ct state { established, related } accept — Step 4: Allow established connections.
sudo nft add rule inet filter input ct state { established, related } acceptnft add rule inet filter input ct state invalid drop — Step 5: Drop invalid packets.
sudo nft add rule inet filter input ct state invalid dropnft add rule inet filter input tcp dport { 22, 80, 443 } accept — Step 6: Allow SSH, HTTP, HTTPS.
sudo nft add rule inet filter input tcp dport { 22, 80, 443 } acceptnft add rule inet filter input icmp type echo-request accept — Step 7: Allow ping.
sudo nft add rule inet filter input icmp type echo-request accept Conclusion
With nftables you manage IPv4, IPv6, and bridge filtering in a single, consistent framework instead of four separate legacy tools. Draft new rulesets in an /etc/nftables.conf, validate them with nft -c -f, and enable the nftables service so they survive a reboot. And always test a default policy drop locally first: on a remote server, a forgotten SSH accept quickly costs you access.
Further Reading
- nftables wiki – official documentation and how-tos
- nft(8) – manual page – every option at a glance
- nftables – Wikipedia – background and history