TTR Networks

nftables cheat sheet

nftables is the firewall in every current Debian and most other Linux distributions. These are the commands and rule patterns from the nftables and iptables on Debian lesson, where each one was run on Debian 13 (nftables 1.1.3) with its output shown. The same ruleset style protects the servers in the OpenVPN, WireGuard and PowerDNS lessons.

Everyday commands

TaskCommand
Show everythingnft list ruleset
List the tablesnft list tables
One chain, with rule handlesnft -a list chain inet filter forward
Check a file without loading itnft -c -f /etc/nftables.conf
Load a file (atomic: all or nothing)nft -f /etc/nftables.conf
Check, then reload the saved rulesnft -c -f /etc/nftables.conf && systemctl reload nftables
Load the rules at every bootsystemctl enable --now nftables
Insert a rule at the top of a chainnft insert rule inet filter forward … accept
Delete a rule by its handlenft delete rule inet filter forward handle 9
Add or remove a set elementnft add element inet filter admins { 10.10.0.80 } / nft delete element …
Show a setnft list set inet filter admins
Follow packets through the rulesnft monitor trace (after a rule sets meta nftrace set 1)
See tracked connectionsconntrack -L -p tcp --dport 80
Turn on forwarding (routers)net.ipv4.ip_forward = 1 in /etc/sysctl.d/, then sysctl --system

A router ruleset, piece by piece

table inet filter {
  set admins {
    type ipv4_addr
    elements = { 10.10.0.20 }
  }

  chain input {
    type filter hook input priority filter; policy drop;
    ct state established,related accept
    ct state invalid drop
    iif lo accept
    icmp type { echo-request, destination-unreachable, time-exceeded } accept
    iifname "eth1" ip saddr @admins tcp dport 22 accept comment "SSH from admin PCs"
    limit rate 6/minute burst 5 packets log prefix "nft input drop: "
    counter comment "dropped by the policy"
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
    ct state established,related accept
    ct state invalid drop
    iifname "eth1" oifname "eth0" accept comment "the office to the internet"
    iifname "eth0" oifname "eth1" ct status dnat accept comment "port forwards"
    counter comment "dropped by the policy"
  }
}

table ip nat {
  chain prerouting {
    type nat hook prerouting priority dstnat;
    iifname "eth0" tcp dport 8080 dnat to 10.10.0.80:80
  }
  chain postrouting {
    type nat hook postrouting priority srcnat;
    oifname "eth0" masquerade
  }
}
  • policy drop on input and forward: anything not accepted is dropped, so a forgotten rule fails safe.
  • ct state established,related accept first: replies to allowed traffic are let back in, so the rules only need to describe new connections.
  • input is traffic to the firewall itself; forward is traffic through it. A router needs both, plus IP forwarding.
  • ct status dnat accepts exactly the connections a port forward created, without repeating the addresses.
  • A rate-limited log before the final counter shows what's being dropped (in journalctl -k) without flooding the log.

Sets, maps and rate limits

PatternExample
Named set of addressesip saddr @admins
Anonymous settcp dport { 80, 443 }
Port forwards in one mapdnat ip to tcp dport map @forwards, with 8080 : 10.10.0.80 . 80
Per-source rate limit (dynamic set)update @web_flood { ip saddr limit rate over 10/minute burst 5 packets } drop

iptables on a modern Debian

On Debian 13, iptables is iptables-nft: it writes nftables rules into tables called ip filter, ip nat and so on. Both sets of rules then run on the same hooks, and a packet must pass both: an iptables DROP blocks traffic nftables accepted, and an iptables ACCEPT can't override an nftables drop.

TaskCommand
Which iptables is this?iptables -V (shows nf_tables)
Translate one ruleiptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
Translate a saved rulesetiptables-save > old.rules && iptables-restore-translate -f old.rules

Changing rules without locking yourself out

  1. Check the file: nft -c -f new.conf catches syntax errors, not mistakes in logic.
  2. Schedule a rollback before loading: systemd-run --on-active=60s --timer-property=AccuracySec=1s --unit=nft-rollback nft -f /etc/nftables.conf. Without AccuracySec, systemd may run the timer up to a minute late.
  3. Load the new rules, then open a new SSH session. Your current session survives a bad SSH rule (it's already established); the next login doesn't.
  4. If the new login works, make the change permanent and systemctl stop nft-rollback.timer. If not, wait: the old rules come back by themselves.

Troubleshooting

SymptomCheck
Traffic through the router fails, firewall looks rightsysctl net.ipv4.ip_forward; then the forward chain's counters
Rule seems to be ignoredRule order: nft -a list chain …; an earlier rule matched first. Or an iptables rule on the same hook
Port forward doesn't workThe dnat rule's counter, the forward chain's ct status dnat rule, and the server's route back
log rules print nothing in a containerThe host must allow it: net.netfilter.nf_log_all_netns=1
Docker's rules vanished after flush rulesetflush ruleset removes every table, including other software's; replace one table with destroy table … instead