1)你需要准备什么
一台 入口机:有公网 IP,负责接收外部连接
一台 落地机:运行真实服务,入口机把流量转发到它
明确三样参数:
落地机 IP(DST_IP)
入口机公网网卡名(一般
eth0)要转发的端口(可 1 个或多个)
2)安装 nftables 并启用服务
apt update
apt install -y nftables
systemctl enable --now nftables
3)写入 nftables 规则(DNAT + 仅对 DNAT 连接做 masquerade)
下面这份规则具备几个关键点:
prerouting 做 DNAT:把入口机的端口转到落地机
postrouting 做 SNAT/masquerade:只对“被 DNAT 的连接”做伪装,避免误伤本机其它直连
forward 链过滤:默认 drop,仅放行 DNAT 新建连接与已建立连接
MSS clamp(可选但强烈建议):降低 PMTU/MSS 引发的重传/吞吐抖动,对“落地爆 CPU/小包放大”常见问题很有帮助
你只要替换:
落地IP、端口、网卡名(如有需要)
cat <<'EOF' > /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
define DST_IP = 落地IP
define WAN_IF = "eth0"
# ====== MSS clamp:降低 PMTU/MSS 引发的重传/小包放大 ======
# 保守 MSS=1360,优先求稳;确认整条路径 MTU=1500 且无隧道时可调到 1400/1420
table inet mangle {
chain forward {
type filter hook forward priority -150; policy accept;
ip daddr $DST_IP tcp dport { 端口1, 端口2 } tcp flags syn tcp option maxseg size set 1360
}
}
# ====== NAT ======
table ip nat {
set dst_ports {
type inet_service;
elements = { 端口1, 端口2 }
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
# 只处理公网口进来的新连接(多端口就多写几行)
iifname $WAN_IF tcp dport 端口1 ct state new dnat to $DST_IP:目标端口1
iifname $WAN_IF tcp dport 端口2 ct state new dnat to $DST_IP:目标端口2
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
# 仅对“被 DNAT 的连接”做 masquerade,避免误伤本机直连 DST_IP
ct status dnat ip daddr $DST_IP tcp dport @dst_ports masquerade
}
}
# ====== 转发过滤 ======
table inet filter {
chain forward {
type filter hook forward priority 0; policy drop;
ct state invalid drop
ct state established,related accept
# 仅放行被 DNAT 的新建连接
ct status dnat ip daddr $DST_IP tcp dport { 端口1, 端口2 } ct state new accept
}
}
EOF
端口写法说明(很重要)
{ 端口1, 端口2 }是“数组”只有一个端口就写
{ 57559 }(不需要逗号)prerouting里 每个端口要写一行 dnat(最直观、最不容易错)建议入站端口 = 目标端口(省心),当然也可以不同
网卡名怎么确认
ip addr
看带公网 IP 的网卡,一般就是 eth0。
4)开启 IPv4 转发 + sysctl 参数
cat <<'EOF' > /etc/sysctl.d/99-nft-forward.conf
# IPv4 转发
net.ipv4.ip_forward = 1
# 更积极的 MTU 探测:转发链路常见“吞吐抖动/重传放大”时很有帮助
net.ipv4.tcp_mtu_probing = 1
# conntrack:按需调整(保守值)
net.netfilter.nf_conntrack_max = 32768
net.netfilter.nf_conntrack_buckets = 8192
EOF
5)应用配置(立即生效)
sysctl --system
nft -f /etc/nftables.conf
6)验证是否生效(建议做)
查看规则是否加载:
nft list ruleset
检查入口机是否真的在转发(有连接时看计数会涨):
nft list chain ip nat prerouting
nft list chain inet filter forward
看 conntrack(有新连接时会出现记录):
conntrack -L 2>/dev/null | head
如果没有
conntrack命令:apt install -y conntrack
7)单端口示例(可直接抄)
假设只转发 57559 到落地机 198.1.1.1:57559:
#!/usr/sbin/nft -f
flush ruleset
define DST_IP = 198.1.1.1
define WAN_IF = "eth0"
table inet mangle {
chain forward {
type filter hook forward priority -150; policy accept;
ip daddr $DST_IP tcp dport { 57559 } tcp flags syn tcp option maxseg size set 1360
}
}
table ip nat {
set dst_ports {
type inet_service;
elements = { 57559 }
}
chain prerouting {
type nat hook prerouting priority -100; policy accept;
iifname $WAN_IF tcp dport 57559 ct state new dnat to $DST_IP:57559
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
ct status dnat ip daddr $DST_IP tcp dport @dst_ports masquerade
}
}
table inet filter {
chain forward {
type filter hook forward priority 0; policy drop;
ct state invalid drop
ct state established,related accept
ct status dnat ip daddr $DST_IP tcp dport { 57559 } ct state new accept
}
}
8)完成后的使用方式
到此 入口机转发已完成。你只需要在 落地机 上:
在对应端口启动你的服务
外部用户连接入口机的端口,即会被内核转发到落地机

