nftables from Scratch: Tables, Chains and NAT Examples - 夜莺博客

nftables from Scratch: Tables, Chains and NAT Examples

nftables is the Linux kernel's current packet filtering framework — the default on Debian 12, Ubuntu 22.04+ and RHEL 9 — replacing iptables, ip6tables, arptables and ebtables with one tool, one syntax and atomic rule updates. Unlike iptables there are no predefined tables: you create every table, chain and rule yourself. This guide builds a complete stateful server firewall plus a NAT gateway in /etc/nftables.conf, then shows how to migrate an existing iptables ruleset.

Core Concepts

  • Table — a namespace scoped to an address family: ip, ip6, inet (both, prefer this), arp, bridge, netdev.
  • Base chain — attached to a kernel hook (prerouting, input, forward, output, postrouting) with a type (filter, nat, route) and priority.
  • Policy — the default verdict (accept/drop) when no rule matches.

Install and Enable

sudo apt update && sudo apt install -y nftables
sudo systemctl enable --now nftables

A Stateful Server Firewall

Drop inbound by default, allow established flows, loopback, ICMP and the services you expose:

#!/usr/sbin/nft -f
flush ruleset

table inet filter {
    chain input {
        type filter hook input priority 0; policy drop;
        iif lo accept
        ct state invalid drop
        ct state { established, related } accept
        ip protocol icmp icmp type { echo-request } limit rate 10/second accept
        ip6 nexthdr ipv6-icmp icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } accept
        tcp dport 22 accept
        tcp dport { 80, 443 } accept
        log prefix "nft-drop: " flags all drop
    }
    chain forward { type filter hook forward priority 0; policy drop; }
    chain output  { type filter hook output priority 0; policy accept; }
}

Load and validate atomically — nftables applies a file as one transaction, so a syntax error changes nothing:

sudo nft -c -f /etc/nftables.conf
sudo nft -f /etc/nftables.conf
sudo nft list ruleset

Named Sets: Blocklists without Rule Sprawl

A set matches hundreds of addresses with one rule and hash-based lookups. Entries can be added at runtime without reloading the ruleset:

table inet filter {
    set blocklist { type ipv4_addr; flags timeout; timeout 1h; }
    chain input {
        ip saddr @blocklist drop
    }
}
sudo nft add element inet filter blocklist { 203.0.113.66 }

NAT Gateway: Masquerade and DNAT

Forwarding needs the kernel sysctl plus explicit rules; masquerade rewrites the source of LAN egress, and DNAT exposes internal services:

sudo sysctl -w net.ipv4.ip_forward=1

table ip nat {
    chain postrouting {
        type nat hook postrouting priority srcnat;
        oifname "eth0" masquerade
    }
    chain prerouting {
        type nat hook prerouting priority dstnat;
        tcp dport 2222 dnat to 192.168.1.20:22
    }
}

Two gotchas from production: never run flush ruleset on a host with Docker, firewalld or libvirt — it deletes their tables too (scope flushes to your own table); and never run iptables and nftables side by side on the same hooks, since both program the same kernel subsystem.

Migrating from iptables

iptables-translate -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables-save | sudo iptables-restore-translate -f /etc/nftables.conf

Review the translation before loading; complex rules may need cleanup, and translated rules default to the ip family so consolidate into inet if you also had ip6tables rules. Pair the firewall with tc netem for link testing and ethtool when symptoms look like drops at the NIC rather than the filter.

原文链接:https://linuxjunkies.org/guides/configure-nftables-from-scratch