
nft 是当前 Linux 主流发行版默认启用的防火墙工具,iptables 已被标记为“deprecated”。如果你刚接触 nft,别被“下一代”这种说法吓住——它不是全新概念,而是把旧工具的逻辑重写得更干净、更统一。直接上手配置是最快的理解方式,不需要先学完所有语法。
怎么快速建一个能用的 filter 表
多数人只需要过滤入站流量(比如只开 SSH、关掉其他端口),inet 地址簇就足够了:它同时覆盖 IPv4 和 IPv6,避免重复写两套规则。
- 创建表:
nft add table inet filter - 加一条基链:
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }——注意末尾的反斜杠和分号是 shell 要求的转义,policy drop表示默认拒绝,这是安全起点 - 允许回环:
nft add rule inet filter input iifname "lo" accept - 允许已建立连接返回:
nft add rule inet filter input ct state established,related accept(ct是conntrack的缩写)
执行完这四条,nft list ruleset 就能看到完整结构。此时 SSH 还连不上——因为没放行 22 端口,这点和 iptables 一样,必须显式添加。
为什么 tcp dport 22 accept 有时不生效
常见现象:加了 SSH 端口规则但仍连不上,nft list ruleset 显示规则存在,ss -tlnp | grep :22 也确认 sshd 在监听。问题往往出在链的执行顺序或匹配条件太窄:
-
tcp dport 22只匹配 TCP,如果客户端发的是 SYN 包但被中间设备改了协议类型(极少见),或你误用了ip protocol tcp冗余写法,都可能跳过 - 规则位置很重要:
nft按链内顺序逐条匹配,ct state invalid drop这类兜底规则如果放在 SSH 规则前面,会导致新连接被提前丢弃 - IPv6 地址族未覆盖:若只在
ip表里加规则,而客户端走的是 IPv6,就会失效;用inet表可一并解决
稳妥写法:nft add rule inet filter input tcp dport 22 ct state new accept,明确限定只放行新连接的 SYN 包,既安全又精准。
nft 规则重启后丢失怎么办
命令行添加的规则只存在于内存,系统重启即清空。持久化有且仅有一个推荐路径:
- 把规则导出到文件:
nft list ruleset > /etc/nftables.conf - 确保 systemd 服务启用:
systemctl enable nftables(部分发行版如 RHEL 8+/AlmaLinux 默认启用,Debian/Ubuntu 需手动安装nftables包并启用服务) - 检查服务状态:
systemctl status nftables,确认 Loaded 行指向/etc/nftables.conf
不要试图用 rc.local 或自定义脚本 reload 规则——nftables 服务本身就在启动时读取该文件并载入,多此一举反而易出错。另外,/etc/sysconfig/nftables.conf 是旧版 RHEL/CentOS 7 的路径,新版统一用 /etc/nftables.conf。
日志和调试最实用的三招
规则不生效时,光看 nft list 不够,得确认数据包是否真走到那条规则:
- 加
counter统计命中次数:nft add rule inet filter input tcp dport 22 counter accept,然后nft list chain inet filter input查看pktcnt和bytecnt是否增长 - 加
log输出内核日志:nft add rule inet filter input tcp dport 22 log prefix "SSH-ATTEMPT: " counter accept,再journalctl -k | grep "SSH-ATTEMPT"实时观察 - 用
tcpdump对比验证:tcpdump -i any port 22 and host <client-ip></client-ip>确认包是否到达本机,再结合nft计数器判断是被丢弃还是根本没匹配
注意:log 语句不终止规则执行,所以要跟 accept 或 drop 显式配对;否则包会继续往下匹配,可能被后续规则意外放行或拦截。
真正麻烦的不是语法,而是规则顺序、地址簇选择、以及忘记 counter 和 log 这两个调试锚点。写完一条规则,立刻用 counter 验证是否命中,比反复猜错因高效得多。


















