Nftables 详细笔记
本文是一份可直接上手的 nftables 实战手册:从安装、启用、规则编写到常见场景(仅放行必要端口、KDE Connect、端口转发/NAT、VPN/WireGuard、速率限制、日志)与排错
快速上手:
1 2 3 4 5 6 7 8 9 10 11
| sudo nft list ruleset
sudo nft -f /etc/nftables.conf
sudo nft -c -f /etc/nftables.conf
sudo nft flush ruleset
|
服务与持久化(systemd):
1 2
| sudo systemctl enable --now nftables.service sudo systemctl status nftables.service
|
1、安装与启用(按发行版)
1.1、Arch Linux
1 2 3 4 5 6
| sudo pacman -S nftables
sudo pacman -Q nftables
sudo systemctl enable --now nftables.service
|
1.2、Debian / Ubuntu / Linux Mint
1 2 3
| sudo apt update sudo apt install nftables sudo systemctl enable --now nftables.service
|
提示(Ubuntu/UFW):Ubuntu 的 UFW 默认已经基于 nft 后端。如果你要直接写 nft 规则,不建议同时启用/使用 UFW,以免冲突。要么只用 UFW,要么停用 UFW 转用纯 nft
1.3、Fedora / RHEL / CentOS / Rocky / AlmaLinux
这些系统默认启用 firewalld(其后端也是 nft)二选一:
- 继续用 firewalld(推荐给新手)
- 停用 firewalld,改用纯 nftables(适合熟悉 nft 的用户)
1 2 3 4
| sudo dnf install nftables sudo systemctl disable --now firewalld sudo systemctl enable --now nftables.service
|
远程服务器请谨慎:停用 firewalld 前先准备好等效的 nft 规则,避免把自己锁在门外
1.4、openSUSE
1 2
| sudo zypper install nftables sudo systemctl enable --now nftables.service
|
2、规则集结构与写法
nftables 结构:ruleset → table → chain → rule
- family:ip(仅 IPv4), ip6(仅 IPv6), inet(IPv4+IPv6 同写),arp,bridge 等
- 常用 family:inet(推荐,双栈统一书写)
- hook(挂载点):input/forward/output(filter),prerouting/postrouting(nat)
- policy:链的默认策略,常用 accept 或 drop
3、最小安全模板(建议默认)
将以下内容保存到 /etc/nftables.conf:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #!/usr/sbin/nft -f flush ruleset
table inet filter { chain input { type filter hook input priority filter; policy drop;
ct state invalid drop comment "早丢无效连接" ct state { established, related } accept comment "允许已跟踪连接" iif lo accept comment "允许本机环回" ip protocol icmp accept comment "允许 IPv4 ICMP" meta l4proto ipv6-icmp accept comment "允许 IPv6 ICMP"
tcp dport ssh accept comment "开放 SSH 22/TCP(建议配合密钥/端口变更)" # 示例:开放 Web tcp dport {80,443} accept
# 其它需要的端口在此按需添加: # tcp dport { 8080, 9090 } accept # udp dport 51820 accept # WireGuard 示例 }
chain forward { type filter hook forward priority filter; policy drop; }
chain output { type filter hook output priority filter; policy accept; } }
|
应用:
1 2 3
| sudo nft -c -f /etc/nftables.conf sudo systemctl restart nftables.service sudo nft list ruleset
|
4、进阶模板(含多端口放行)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| #!/usr/sbin/nft -f flush ruleset
table inet filter { chain input { type filter hook input priority filter; policy drop;
ct state invalid drop comment "早丢无效连接" ct state { established, related } accept comment "允许已跟踪连接" iif lo accept comment "允许 loopback" ip protocol icmp accept comment "允许 IPv4 ICMP" meta l4proto ipv6-icmp accept comment "允许 IPv6 ICMP"
# SSH tcp dport ssh accept comment "允许 SSH"
# 你需要的端口(TCP/UDP) tcp dport { 80, 443, 8080, 8090, 1090, 1080, 33612, 23361, 5000, 2017, 10170, 1314 } accept comment "允许指定 TCP" udp dport { 80, 443, 8080, 8090, 1090, 1080, 33612, 23361, 5000, 2017, 10170, 1314 } accept comment "允许指定 UDP"
# KDE Connect tcp dport 1716-1764 accept comment "KDE Connect TCP" udp dport 1716-1764 accept comment "KDE Connect UDP"
# 基础抗扫描:限制主机发来的包速率(非严格防护,仅示例) pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited
counter comment "统计所有被拒" }
chain forward { type filter hook forward priority filter; policy drop; }
chain output { type filter hook output priority filter; policy accept; } }
|
保存为 /etc/nftables.conf 并重载:
1
| sudo systemctl restart nftables.service
|
5、常见场景配置
1.1、仅放行指定服务端口
- 规则放在 table inet filter 的 input 链里
- 常用:SSH(22)、HTTP(80)、HTTPS(443)、WireGuard(51820/UDP) 等
- 出站(output)默认一般 accept 即可
1.2、出站流量说明:为什么没放行端口也能访问外网
- 浏览器访问网页属于出站(output)连接,服务器回复会匹配 ct state established,related 放行,不依赖 input 端口放行
- 别人访问你的机器是入站(input)连接,才会命中 input 链的端口判断
对照:
- 你本机 curl -x 127.0.0.1:2017 https://example.com → 出站,不受 input 限制
- 别人手机连你 你的IP:2017 → 入站,若未 tcp dport 2017 accept 会被拦
1.3、NAT 上网共享(Masquerade)
用途:你的主机作为网关,让内网通过它访问外网
1)先开启内核转发:
1 2 3 4 5
| echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-nftables-forward.conf
echo 'net.ipv6.conf.all.forwarding=1' | sudo tee -a /etc/sysctl.d/99-nftables-forward.conf sudo sysctl --system
|
2)在 nftables 里新增 nat 表(把 define wan 改成你的外网网卡名,如 eth0/enp3s0/wlan0):
1 2 3 4 5 6 7 8 9 10 11 12
| table inet nat { define wan = "eth0"
chain prerouting { type nat hook prerouting priority dstnat; policy accept; }
chain postrouting { type nat hook postrouting priority srcnat; policy accept; oifname $wan masquerade comment "源 NAT:内网经 $wan 出口上网" } }
|
与 filter 表并存:把这个 table inet nat { … } 加到 /etc/nftables.conf 中即可。
1.4、端口转发(DNAT)
把外网的 80 端口转发到内网 192.168.1.10:8080:
1 2 3 4 5 6 7 8 9 10 11 12
| table inet nat { chain prerouting { type nat hook prerouting priority dstnat; policy accept; tcp dport 80 dnat to 192.168.1.10:8080 }
chain postrouting { type nat hook postrouting priority srcnat; policy accept; # 若需回流 SNAT: ip saddr 192.168.1.0/24 ip daddr 192.168.1.10 tcp dport 8080 masquerade } }
|
1.5、WireGuard 常用规则
WireGuard 默认 UDP 端口(示例 51820):
1 2
| # filter 表 input 链里 udp dport 51820 accept comment "WireGuard"
|
1.6、基础抗扫描/限速与日志
限速示例(SYN 新建连接每 IP 每秒 25 次):
1
| tcp flags & (syn|ack) == syn limit rate over 25/second drop comment "limit syn flood"
|
记录被拒包到日志(需内核日志支持,配合 journalctl):
1 2 3 4
| reject with icmpx type admin-prohibited # 或记录: log prefix "nft-drop: " group 0 drop
|
查看:
1
| sudo journalctl -k | grep nft-drop
|
1.7、临时调试与持久化
临时添加规则(重启服务后丢失):
1
| sudo nft add rule inet filter input tcp dport 9000 accept
|