nftables NAT: Masquerade and Port Forwarding Guide - 夜莺博客

nftables NAT: Masquerade and Port Forwarding Guide

nftables replaces iptables as the default packet filter on every mainstream distribution, and its NAT syntax is both simpler and more predictable - a single dnat statement replaces the old PREROUTING/OUTPUT pair of rules, and masquerade no longer needs a separate module. This guide covers the three NAT operations engineers actually use daily: source NAT for outbound internet access, destination NAT for publishing internal services, and the port-forwarding combination of the two that so often breaks because only half of it is configured.

NAT Table, Chains and Hooks

NAT rules live in a table of type nat with two chains. Prerouting runs before the routing decision and is where DNAT belongs. Postrouting runs after the routing decision and is where SNAT and masquerade belong. Getting the hook wrong is the single most common nftables NAT mistake: a masquerade rule in prerouting never matches.

nft add table ip nat
nft 'add chain ip nat prerouting { type nat hook prerouting priority dstnat ; }'
nft 'add chain ip nat postrouting { type nat hook postrouting priority srcnat ; }'

Masquerade for Outbound Access

Masquerade rewrites the source address to whatever address the outgoing interface currently holds, which is exactly what you want on DHCP or PPPoE uplinks where the address changes. Use plain SNAT when the uplink address is static, because it does not clear conntrack entries on interface events.

nft add rule ip nat postrouting oifname "eth0" masquerade
# or a fixed address
nft add rule ip nat postrouting ip saddr 10.0.0.0/24 oifname "eth0" snat to 203.0.113.10

Masquerade only makes sense from the postrouting chain of a NAT-type chain - the kernel needs a routing decision to know which address to substitute.

Port Forwarding with DNAT

Destination NAT rewrites the destination address and optionally the port. A DNAT rule in prerouting plus a forwarding filter rule is enough to publish a service:

nft add rule ip nat prerouting iifname "eth0" tcp dport 8443 dnat to 10.0.0.20:443
nft add rule ip nat prerouting iifname "eth0" udp dport 53 dnat to 10.0.0.53:53

# allow the forwarded traffic through the filter table
nft add rule inet filter forward ct state established,related accept
nft add rule inet filter forward ip daddr 10.0.0.20 tcp dport 443 accept

Without the matching forward rule the packet is rewritten and then dropped by the filter policy, which produces a confusing symptom: the counter on the DNAT rule increments while the client sees a timeout.

The Hairpin Problem

Clients inside the same subnet as the forwarded server cannot reach it through the public address, because the response bypasses the gateway. Add a masquerade rule scoped to that source and destination:

nft add rule ip nat postrouting ip saddr 10.0.0.0/24 ip daddr 10.0.0.20 masquerade

Verifying and Debugging

nft list table ip nat
nft list ruleset
nft -a list chain ip nat prerouting     # show rule handles
conntrack -L | grep 8443
nft monitor trace

Counters are your friend. If the DNAT rule shows zero packets, the packet never reached prerouting - check the ingress interface name and any earlier filter drop. If counters increment but no connection is established, add a temporary log statement or use nft monitor trace to follow the packet through the ruleset.

Port Ranges and Rule Modification

nft add rule ip nat prerouting tcp dport 3000-3010 dnat to 10.0.0.30
nft 'add rule ip nat prerouting tcp dport { 80, 443 } dnat to 10.0.0.20'
nft -a list chain ip nat prerouting
nft delete rule ip nat prerouting handle 12

Rules are edited by handle, so always list with -a before deleting. For a full firewall design with stateful filtering see nftables stateful firewall with conntrack, and if you are porting existing rulesets, nftables migration from iptables, ipset, sets and maps covers the mechanical translation.

Making Rules Persistent

Rules added with the CLI vanish on reload. Dump them into a file and load it at boot:

nft list ruleset > /etc/nftables.conf
systemctl enable --now nftables
nft -f /etc/nftables.conf

Keep the file as the single source of truth and treat interactive nft add commands as experiments only.

原文链接:https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)