在Debian 10(Buster)及之后的版本中,nftables已经成为默认的防火墙框架,逐步取代了传统的iptables。如果你正在维护一台Debian服务器,需要把现有的iptables规则迁移到nftables,核心思路就是:先用iptables-nft兼容层跑通现有规则,再逐步用原生nftables语法重写,最终完全脱离iptables。下面我会从安装、规则转换、实战迁移到验证优化,一步步讲清楚整个过程。
为什么Debian要从iptables转向nftables
iptables已经维护了二十多年,它的底层架构基于多个独立的工具(iptables、ip6tables、ebtables、arptables),规则集分散、语法不统一,性能也逐渐跟不上现代内核的需求。nftables是Linux内核从3.13版本开始引入的新一代包过滤框架,它统一了IPv4、IPv6、ARP、桥接等多种协议的过滤规则,语法更简洁,性能更高,而且支持原子性规则更新——也就是说,你可以一次性加载一整组规则,不会出现加载一半导致防火墙短暂失效的情况。Debian从Buster开始默认使用nftables,到Bookworm已经彻底移除了iptables的独立包,只保留了iptables-nft作为兼容层。
第一步:确认系统环境并安装必要工具
在开始迁移之前,先确认你的Debian版本和当前防火墙状态。登录服务器后执行以下命令:
cat /etc/debian_version nft list ruleset
如果nft list ruleset返回空或者报错,说明nftables还没有启用任何规则。接下来安装nftables和iptables兼容工具:
apt update apt install nftables iptables
安装完成后,启用nftables服务并设置开机自启:
systemctl enable nftables systemctl start nftables
注意:如果你之前用的是ufw或者firewalld,建议先禁用它们,避免规则冲突。执行:
systemctl disable ufw systemctl stop ufw
第二步:导出现有iptables规则
在迁移之前,你需要把当前iptables的规则完整导出来。用iptables-save命令可以把所有规则输出到文件:
iptables-save > /root/iptables-backup.txt
如果你同时用了IPv6规则,也要导出ip6tables:
ip6tables-save > /root/ip6tables-backup.txt
打开备份文件看一下内容,典型的iptables规则长这样:
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -i lo -j ACCEPT -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT -A INPUT -p tcp --dport 22 -j ACCEPT -A INPUT -p tcp --dport 80 -j ACCEPT -A INPUT -p tcp --dport 443 -j ACCEPT -A INPUT -j DROP COMMIT
这段规则的意思是:默认丢弃所有入站和转发流量,允许本地回环、已建立连接、SSH(22)、HTTP(80)、HTTPS(443),其余全部拒绝。
第三步:将iptables规则转换为nftables语法
nftables的语法结构和iptables完全不同。iptables是基于"表-链-规则"的三层结构,而nftables是"表-链-规则-表达式"的扁平结构,而且表的类型也不一样。nftables主要有这几种表类型:
filter表:用于包过滤(对应iptables的filter表)
nat表:用于网络地址转换(对应iptables的nat表)
route表:用于路由决策
inet表:同时处理IPv4和IPv6(这是nftables的一大优势)
下面是把上面那段iptables规则转换成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
# 允许SSH
tcp dport 22 accept
# 允许HTTP
tcp dport 80 accept
# 允许HTTPS
tcp dport 443 accept
# 拒绝其余所有
drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
几个关键转换点要注意:iptables里的-i lo对应nftables的iif "lo";-m conntrack --ctstate对应ct state;-p tcp --dport对应tcp dport;默认策略DROP在nftables里用policy drop来声明。
第四步:处理NAT规则的迁移
如果你的服务器做了端口转发或者 masquerade,这部分规则要放到nat表或者inet表的nat链里。假设你原来有这样的iptables NAT规则:
*nat :PREROUTING ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A POSTROUTING -o eth0 -j MASQUERADE -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80 COMMIT
转换成nftables写法:
table ip nat {
chain postrouting {
type nat hook postrouting priority 100;
oifname "eth0" masquerade
}
chain prerouting {
type nat hook prerouting priority -100;
tcp dport 8080 redirect to :80
}
}
这里有个细节:nftables里用oifname代替了iptables的-o,用redirect to代替了REDIRECT。而且nftables支持在同一条链里混合IPv4和IPv6规则(如果用inet表的话),但如果你只处理IPv4,就用ip类型的表。
第五步:加载和测试新规则
把转换好的规则保存为文件,比如/etc/nftables.conf,然后用nft命令加载:
nft -f /etc/nftables.conf
加载之后立刻验证规则是否生效:
nft list ruleset
这时候你应该能看到完整的规则集。然后做实际测试:从另一台机器尝试SSH连接、访问80和443端口,确认正常;尝试访问一个未开放的端口,确认被拒绝。如果发现SSH连不上了,别慌——用控制台或者带外管理进去,把input链的policy改成accept,先恢复访问再排查问题。
第六步:设置nftables持久化
Debian的nftables包自带了systemd服务,规则文件默认放在/etc/nftables.conf。确认文件存在并且内容正确后,重启服务使其生效:
systemctl restart nftables systemctl status nftables
如果你之前用iptables-persistent来保存规则,现在不需要了。nftables的持久化就是/etc/nftables.conf这个文件本身,systemd启动时会自动加载。建议做个备份:
cp /etc/nftables.conf /etc/nftables.conf.bak
第七步:清理iptables兼容层
规则迁移完成并稳定运行一段时间后(建议至少观察一周),你可以卸载iptables包,彻底告别兼容层:
apt remove iptables apt autoremove
卸载后再确认nftables仍然正常工作:
nft list ruleset
迁移过程中的常见坑和解决方案
第一个坑:规则顺序问题。iptables是按链内顺序逐条匹配,nftables也是,但nftables的hook优先级(priority)会影响链的执行顺序。如果你有多条链,注意设置正确的priority值,数字越小优先级越高。
第二个坑:连接跟踪状态。iptables里用-m conntrack --ctstate,nftables里简化为ct state,但要注意nftables的ct模块功能更强,还支持ct helper、ct mark等高级特性,迁移时不要遗漏。
第三个坑:接口名称。iptables用-i eth0,nftables用iifname "eth0"或者oifname "eth0"。如果你的网卡名称是ens33、enp0s3这种新命名方式,一定要用实际名称,不要想当然写eth0。
第四个坑:Docker和容器网络。如果你的服务器跑了Docker,Docker会自己管理iptables规则,直接迁移可能导致容器网络异常。建议在迁移前停止Docker,迁移完成后再启动,或者单独为Docker的规则创建独立的nftables链。
进阶技巧:用nftables的集合和映射简化规则
nftables支持set和map数据结构,这是iptables做不到的。比如你要封禁一批IP地址,不用写几十条规则,可以这样:
table inet filter {
set blacklist {
type ipv4_addr
elements = { 192.168.1.100, 10.0.0.5, 172.16.0.99 }
}
chain input {
type filter hook input priority 0; policy drop;
ip saddr @blacklist drop
iif "lo" accept
ct state established,related accept
tcp dport { 22, 80, 443 } accept
drop
}
}
这种写法不仅规则更短,而且以后要添加或删除封禁IP,只需要修改set里的elements,不用动规则本身。这在管理大量IP黑名单时非常高效。
总结
从iptables迁移到nftables不是一键完成的事情,但也没有想象中复杂。核心流程就是:导出旧规则、理解语法差异、逐条转换、加载测试、持久化、清理旧工具。Debian官方推荐的路径就是通过iptables-nft兼容层过渡,最终完全切换到原生nftables。掌握了这套方法,你不仅能完成迁移,还能利用nftables更强大的语法特性把防火墙规则写得更清晰、更高效、更易维护。对于生产环境,建议在维护窗口操作,提前做好快照和回滚方案,确保万无一失。
