CentOS 7/8/9系统中,nftables已经成为iptables的官方替代方案,从CentOS 8开始,iptables命令实际上是通过nftables后端的兼容层来执行的。迁移的核心注意事项有三点:第一,规则语法完全不同,不能直接复制iptables规则文件;第二,nftables采用表、链、规则的层级结构,需要重新规划规则集;第三,迁移过程中必须保留回退方案,避免防火墙失效导致服务器失联。下面我把整个迁移流程、常见坑点和最佳实践一次性讲清楚。
一、为什么CentOS要从iptables迁移到nftables
iptables和iptables-nft是两套不同的后端实现。传统iptables使用内核netfilter模块,规则按表(filter、nat、mangle、raw)分类,每张表下有独立的链。而nftables是一个统一的包过滤框架,所有表、链、规则都在同一个命令行工具下管理,语法更简洁,性能更好,支持原子规则更新(一次加载全部规则,不会出现规则中间态)。CentOS 8和9默认使用nftables,iptables命令只是通过兼容层翻译成nftables规则执行。这意味着你以为在用iptables,实际上底层已经是nftables了,直接迁移到原生nftables语法才是正确方向。
二、迁移前必须做的准备工作
在动手之前,有几件事必须确认。首先,备份现有防火墙规则,不管你现在用的是iptables还是firewalld,都要导出当前规则。其次,确认系统上是否安装了nftables工具包,CentOS 8/9默认已安装,但最好执行一次确认:
yum install nftables -y systemctl enable nftables systemctl start nftables
第三,关闭firewalld或者确保它不会干扰nftables的运行。如果你用的是firewalld,需要先停掉它:
systemctl stop firewalld systemctl disable firewalld
第四,通过SSH远程操作时,建议开一个备用终端或者通过带外管理(如IPMI/iLO)保持连接,防止规则写错把自己锁在外面。
三、导出现有iptables规则作为参考
虽然不能直接导入,但导出的规则可以作为逻辑参考。执行以下命令查看当前iptables规则:
iptables -L -n -v --line-numbers iptables -t nat -L -n -v --line-numbers iptables -t mangle -L -n -v --line-numbers iptables -t raw -L -n -v --line-numbers
把输出结果保存到文件里,后续写nftables规则时对照着逐条转换。特别注意NAT规则和自定义链的逻辑,这些是最容易出错的地方。
四、nftables的基本语法结构
nftables的规则组织方式是:表(table)→ 链(chain)→ 规则(rule)。常用的表有filter(过滤)、nat(地址转换)、route(路由)。和iptables不同,nftables的链不再按表预定义,而是你自己创建,然后绑定到特定的钩子(hook)和优先级(priority)。
查看当前nftables规则集的命令:
nft list ruleset
创建一个基本规则集的框架:
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
这里inet表示同时处理IPv4和IPv6,如果只需要IPv4可以用ip,只需要IPv6用ip6。type filter表示过滤表,hook input表示挂载到输入钩子,priority 0是默认优先级,policy是默认策略。
五、iptables规则到nftables的逐条转换方法
这是迁移最核心的部分。下面按常见场景逐一说明转换方式。
场景一:允许特定端口入站。iptables写法是:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT
转换为nftables:
table inet filter {
chain input {
type filter hook input priority 0; policy accept;
tcp dport { 22, 80, 443 } accept
}
}
场景二:允许已建立的连接。iptables写法:
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
nftables写法:
ct state established,related accept
场景三:NAT规则(端口转发)。iptables写法:
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -j MASQUERADE
nftables写法需要单独建nat表:
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
tcp dport 8080 dnat to 192.168.1.100:80
}
chain postrouting {
type nat hook postrouting priority 100;
ip saddr 192.168.1.0/24 masquerade
}
}
注意priority的值:prerouting钩子通常用-100,postrouting用100,这和iptables中PREROUTING在DNAT阶段、POSTROUTING在SNAT阶段的逻辑一致。
六、迁移过程中的关键注意事项
第一,规则加载是原子性的。nftables使用nft -f命令加载规则文件时,要么全部成功,要么全部回滚。这比iptables逐条执行安全得多,但也意味着如果规则文件有语法错误,整个规则集都不会生效,防火墙会变成空的(取决于默认策略)。所以一定要在规则文件最后设置合理的默认策略,或者先用nft list ruleset确认当前状态再加载新规则。
第二,不要混淆nftables和iptables-nft。CentOS 8上iptables命令实际上调用的是iptables-nft后端,它的规则存储在/etc/sysconfig/iptables文件中,但底层是nftables。如果你同时用nft命令和iptables命令管理规则,会产生冲突。迁移期间建议完全停用iptables服务:
systemctl stop iptables systemctl disable iptables
第三,关于连接跟踪。nftables使用ct模块,语法比iptables的conntrack更简洁,但功能完全等价。如果你的规则依赖conntrack的特定状态匹配,比如NEW、INVALID等,都可以直接用ct state来写。
第四,日志规则的转换。iptables中用-j LOG,nftables中用log前缀:
tcp dport 22 log prefix "SSH connection: " accept
第五,自定义链的处理。iptables中常用自定义链来组织规则,nftables中虽然也支持自定义链,但更推荐直接在主链中用集合(set)和映射(map)来管理复杂规则,这样性能更好,规则更易维护。
七、完整的迁移规则文件模板
下面给一个生产环境常用的完整nftables规则文件模板,你可以根据实际需求修改:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 允许本地回环
iif lo accept
# 允许已建立和相关连接
ct state established,related accept
# 允许ICMP
ip protocol icmp accept
# 允许SSH
tcp dport 22 accept
# 允许HTTP/HTTPS
tcp dport { 80, 443 } accept
# 允许特定管理端口
tcp dport 8443 accept
# 拒绝其他并记录日志
log prefix "Dropped input: " drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority -100;
# 端口转发示例
tcp dport 8080 dnat to 192.168.1.100:80
}
chain postrouting {
type nat hook postrouting priority 100;
ip saddr 192.168.1.0/24 masquerade
}
}
将此内容保存为/etc/nftables.conf,然后执行nft -f /etc/nftables.conf加载。确认规则生效后,执行systemctl enable nftables确保开机自启。
八、迁移后的验证和回退方案
加载新规则后,立即执行nft list ruleset检查规则是否正确。然后用外部工具从另一台机器测试连通性:SSH能否连上、Web服务是否正常、NAT转发是否工作。如果发现问题,立即回退。回退方法有两种:一是如果你保留了iptables规则文件,可以重新启用iptables服务并加载旧规则;二是直接清空nftables规则集:
nft flush ruleset
但清空后防火墙等于没有任何规则,所以更安全的做法是提前写好一个"紧急放行"规则文件,包含至少允许SSH的最小规则集,放在手边随时可以加载。
九、常见问题和避坑总结
坑一:CentOS 7默认没有nftables,需要手动安装并确认内核版本支持(3.10以上)。CentOS 7的内核可能需要升级才能完整支持nftables。
坑二:firewalld和nftables不能同时运行。如果你的系统一直用firewalld,迁移时必须先彻底停掉它,否则两者会争夺netfilter钩子导致规则混乱。
坑三:Docker和Kubernetes等容器平台会自己管理iptables/nftables规则。如果服务器跑了容器服务,迁移前要确认容器网络是否依赖特定规则,避免迁移后容器网络中断。
坑四:nftables的集合(set)功能非常强大,可以用来替代iptables中大量重复的IP封禁规则。比如封禁一个IP段:
table inet filter {
set blackhole {
type ipv4_addr
elements = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
}
chain input {
type filter hook input priority 0; policy drop;
ip saddr @blackhole drop
}
}
这种写法比iptables中写几十条规则高效得多,也是迁移时值得优化的地方。
十、总结
CentOS从iptables迁移到nftables不是简单的命令替换,而是规则逻辑的重新梳理。核心步骤是:备份旧规则→安装nftables→停掉iptables和firewalld→按新语法重写规则→加载验证→设置开机自启。整个过程中最重要的是保留回退手段和确保SSH不被锁死。nftables在语法简洁性、性能和原子更新方面都优于iptables,是未来Linux防火墙的标准方向,尽早迁移、尽早受益。
