nftables 防火墙进阶:从 iptables 迁移到 Linux 内核级网络防护
如果你还在用 iptables 管理服务器或软路由的防火墙规则,这篇文章可能比你想象的更重要。2024 年初,Debian 12 已经将 nftables 设为默认防火墙框架;2025 年,RHEL 系列全面弃用 iptables;而到了 2026 年,大多数 Linux 发行版的 iptables 命令实际上只是一个指向 nftables 的兼容层。
迁移不是选择,而是必然。 但很多人卡在「iptables 规则怎么写」到「nftables 规则怎么写」的转换环节。本文将以实战为导向,带你完成从 iptables 到 nftables 的平滑迁移,并构建一套生产级别的家庭/服务器防火墙体系。
为什么要从 iptables 迁移到 nftables?
这不是一个「新版本更好看」的升级,而是架构层面的根本性改进。
iptables 的历史包袱
iptables 诞生于 2001 年,基于 Netfilter 框架设计。经过二十多年的发展,它积累了几个无法忽视的问题:
- 多套工具并存:IPv4 用 iptables,IPv6 用 ip6tables,arp 过滤用 arptables,桥接用 ebtables。管理一个完整的防火墙需要维护四套独立的规则集,规则重复且容易不一致。
- 线性匹配性能差:规则按顺序逐条匹配,当规则数量达到几百条时,每个数据包的匹配开销显著增加。
- 原子更新困难:修改规则时需要 flush 整个链,这会导致短暂的网络中断——在生产环境中这是不可接受的。
- 规则可读性差:一条复杂的 NAT + 过滤规则可能需要十几行 iptables 命令,逻辑关系不够直观。
nftables 的架构优势
nftables 从 2014 年进入 Linux 3.13 内核开始,经过十余年的迭代,已经非常成熟。它的核心设计解决了 iptables 的所有痛点:
| 特性 | iptables | nftables |
|---|---|---|
| 统一框架 | 四套独立工具 | 单一线程管理 IPv4/IPv6/arp/bridge |
| 匹配性能 | 线性匹配 O(n) | 集合/映射 O(1) |
| 原子更新 | 需要 flush | 单条命令原子替换 |
| 规则语法 | 命令堆叠 | 声明式配置 |
| 日志输出 | 固定格式 | 自定义前缀和内容 |
最关键的一点:nftables 的集合(set)和映射(map)功能,让 IP 黑白名单、端口开放列表等操作从「逐条添加规则」变成了「维护一个数据结构」,在规则数量多的场景下性能差距可达数十倍。
核心概念对照:从 iptables 思维到 nftables 思维
迁移的第一步是理解概念的映射关系。iptables 和 nftables 不是简单的命令替换,而是思维方式的转变。
层级结构对照
iptables 的层级是:Table → Chain → Rule。
nftables 的层级是:Table → Chain → Rule,但更加灵活:
| iptables 概念 | nftables 概念 | 说明 |
|---|---|---|
| filter/nat/mangle/raw 表 | 任意命名的表(type 字段指定用途) | nftables 的表没有预定义名称,通过 type 字段区分 filter/nat 等用途 |
| INPUT/FORWARD/OUTPUT 链 | hook 链(指定 hook 类型和优先级) | nftables 用 hook filter input priority 0 这样的声明替代固定链名 |
| -A / -I / -D 操作 | add / insert / delete rule | 命令语义更清晰,接近自然语言 |
| 无集合概念 | set / map(核心优势) | IP 列表、端口列表可动态增删,无需重载规则 |
常用规则对照速查
下面是日常运维中最常用的规则转换对照:
# ===== 基础过滤规则 =====
# iptables: 允许已建立连接
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# nftables: 等价写法
nft add rule inet filter input ct state established,related accept
# iptables: 允许回环接口
iptables -A INPUT -i lo -j ACCEPT
# nftables
nft add rule inet filter input iifname lo accept
# iptables: 丢弃无效连接
iptables -A INPUT -m conntrack --ctstate invalid -j DROP
# nftables
nft add rule inet filter input ct state invalid drop
# ===== NAT 规则 =====
# iptables: 端口转发 8080 → 80
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j REDIRECT --to-port 80
# nftables
nft add rule ip nat prerouting tcp dport 8080 redirect to :80
# iptables: MASQUERADE(软路由常见场景)
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# nftables
nft add rule ip nat postrouting oifname eth0 masquerade
# ===== 速率限制 =====
# iptables: 限制 SSH 每分钟最多 4 个新连接
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 4 -j REJECT
# nftables
nft add rule inet filter input tcp dport 22 ct state new limit rate 4/minute accept
实战:构建完整的家庭/服务器防火墙
理论说再多不如动手做。下面我们以一台运行 Debian 12 的服务器(或软路由)为例,从零构建一套完整的 nftables 防火墙配置。
第一步:确认 nftables 环境
# 检查 nft 版本
nft --version
# 输出示例:nftables v1.0.6 (Supports Old Service (Liberty) v3)
# 检查内核模块
lsmod | grep nf_tables
# 查看当前规则(应该是空的或只有 iptables 兼容层规则)
nft list ruleset
第二步:编写声明式配置文件
nftables 的最大优势之一是支持声明式配置文件。我们将所有规则写在一个文件中,然后通过一条命令加载:
# /etc/nftables.conf
#!/usr/sbin/nft -f
# 清空现有规则(原子操作,避免中断)
flush ruleset
# ===== 定义可复用的集合 =====
# 允许访问的管理 IP 列表(白名单)
# 生产环境中建议使用 CIDR 范围,不要只写单个 IP
define ADMIN_IPS = { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
# 对外提供服务的端口
define PUBLIC_TCP_PORTS = { 22, 80, 443 }
# 需要限速的敏感服务端口
define RATE_LIMIT_PORTS = { 22, 3306, 5432 }
# 内网接口(根据你的实际情况修改)
define LAN_IFACE = "eth1"
define WAN_IFACE = "eth0"
# ===== 基础过滤表 =====
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# 1. 回环接口无条件放行
iifname lo accept
# 2. 已建立连接和 Related 连接放行
ct state established,related accept
# 3. 无效连接直接丢弃
ct state invalid drop
# 4. ICMP 放行(允许 ping,但限制速率)
ip protocol icmp limit rate 10/second accept
ip6 nexthdr icmpv6 limit rate 10/second accept
# 5. 管理端口仅允许内网 IP 访问
tcp dport 22 ip saddr $ADMIN_IPS accept
# 6. 公共服务端口放行
tcp dport $PUBLIC_TCP_PORTS accept
# 7. 记录并丢弃其余所有入站流量
log prefix "[nft-dropped-input] " level info
drop
}
chain forward {
type filter hook forward priority 0; policy drop;
# 内网到外网的转发允许
iifname $LAN_IFACE oifname $WAN_IFACE accept
# 外网到内网的转发仅允许已建立连接
iifname $WAN_IFACE oifname $LAN_IFACE ct state established,related accept
# 记录并丢弃其余转发
log prefix "[nft-dropped-forward] " level info
drop
}
chain output {
type filter hook output priority 0; policy accept;
# 出站默认放行,按需添加限制
}
}
# ===== NAT 表 =====
table ip nat {
chain prerouting {
type nat hook prerouting priority -100; policy accept;
# 端口转发示例:外部 8080 → 内网 Web 服务
tcp dport 8080 dnat to 192.168.1.100:80
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
# 内网 MASQUERADE(软路由必备)
oifname $WAN_IFACE masquerade
}
}
第三步:加载配置并验证
# 语法检查(不实际应用)
nft -c -f /etc/nftables.conf
# 加载配置(会先 flush ruleset)
nft -f /etc/nftables.conf
# 查看当前生效的规则
nft list ruleset
# 验证规则数量
nft list chain inet filter input
nft list chain ip nat postrouting
第四步:配置开机自启
# Debian/Ubuntu
systemctl enable nftables
systemctl start nftables
# 确认服务状态
systemctl status nftables
⚠️ 重要提示: 在远程服务器上操作防火墙时,务必在加载新规则之前准备好回退方案。建议在另一个终端窗口保持 SSH 连接,并设置一个定时任务在 5 分钟后恢复 iptables 兼容规则:
# 5 分钟后自动 flush nftables(给自己留退路)
echo 'nft flush ruleset' | at now + 5 minutes
# 确认规则没问题后,取消定时任务
atrm <job_id>
高级技巧:动态 IP 黑名单与自动封禁
nftables 真正的杀手级功能是动态集合。与 iptables 的 ipset 相比,nftables 的 set 内建于框架之中,使用更简单、性能更好。
场景:自动封禁暴力破解 SSH 的 IP
我们可以利用 nftables 的 set 配合 timeout 功能,实现一个轻量级的自动封禁系统,无需依赖 fail2ban:
table inet filter {
# 定义一个带自动过期功能的集合
# 被封禁的 IP 在 1 小时后自动移除
set ssh_blocklist {
type ipv4_addr
flags timeout
timeout 1h
}
chain input {
type filter hook input priority 0; policy drop;
# 先检查是否在黑名单中
ip saddr @ssh_blocklist drop
# 正常规则...
ct state established,related accept
ct state invalid drop
iifname lo accept
# SSH 连接追踪:同一 IP 1 分钟内超过 3 个新连接 → 加入黑名单
tcp dport 22 ct state new add @ssh_blocklist { ip saddr timeout 1h } limit rate over 3/minute drop
# 其余规则...
}
}
这段配置的精髓在于:limit rate over 3/minute 触发了 add @ssh_blocklist 动作,将来源 IP 加入黑名单并设置 1 小时过期。整个过程完全在内核态执行,零性能损耗。
查看和管理黑名单
# 查看当前被封禁的 IP
nft list set inet filter ssh_blocklist
# 手动添加 IP 到黑名单
nft add element inet filter ssh_blocklist { 203.0.113.50 }
# 手动移除 IP
nft delete element inet filter ssh_blocklist { 203.0.113.50 }
迁移 checklist:从 iptables 到 nftables
如果你有一台正在运行的 iptables 服务器,按以下步骤安全迁移:
| 步骤 | 操作 | 验证方法 |
|---|---|---|
| 1 | 备份现有 iptables 规则 | iptables-save > /tmp/iptables-backup.txt |
| 2 | 安装 nftables | apt install nftables && nft –version |
| 3 | 使用 iptables-translate 工具自动转换 | iptables-translate -c /tmp/iptables-backup.txt |
| 4 | 手动优化转换后的规则 | 用 set/map 替换重复规则 |
| 5 | 语法检查 | nft -c -f /etc/nftables.conf |
| 6 | 加载并测试 | 保留 SSH 会话 + at 回退机制 |
| 7 | 禁用 iptables 服务 | systemctl disable iptables |
| 8 | 设置 nftables 开机自启 | systemctl enable nftables |
常见问题与排错
Q1: nftables 和 iptables 能共存吗?
可以,但强烈不建议。两者操作的是同一个 Netfilter 框架,混合使用会导致规则冲突、调试困难和难以预测的行为。迁移时应该一次性切换。
Q2: Docker 的防火墙规则会和 nftables 冲突吗?
Docker 20.10+ 原生支持 nftables 后端。确保 Docker 配置文件中设置 "iptables": false 并使用 "firewalld": false,Docker 会自动通过 nftables 管理其规则。如果仍有问题,可以在 nftables 配置中为 Docker 的 bridge 接口(通常是 docker0)添加例外规则。
Q3: 如何排查规则不生效的问题?
# 开启规则计数器(每条规则显示命中次数)
nft --handle list chain inet filter input
# 查看命中计数为 0 的规则,可能就是这些规则没生效
# 查看内核日志
journalctl -k | grep nft
# 使用 nft monitor 实时查看规则匹配
nft monitor
Q4: IPv6 需要单独配置吗?
不需要。使用 table inet filter(注意是 inet 而不是 ip)就可以同时处理 IPv4 和 IPv6 流量。唯一的例外是 ICMP:IPv4 用 ip protocol icmp,IPv6 用 ip6 nexthdr icmpv6,需要分别处理。
总结:迁移的最佳时机就是现在
nftables 不是 iptables 的”替代品”,而是它的进化。经过十余年的发展,nftables 已经成为 Linux 网络防护的事实标准。对于还在使用 iptables 的系统管理员和运维工程师来说:
- 新部署:直接使用 nftables,不要再碰 iptables
- 现有服务器:制定迁移计划,利用 iptables-translate 工具降低迁移成本
- 软路由/OpenWrt:OpenWrt 23.05+ 已原生支持 nftables,建议启用
防火墙是系统安全的第一道防线。用更现代、更高效、更可维护的工具来守护它,是每个 Linux 管理员应该做出的选择。
作者简介:虾米,专注 Linux 系统运维与网络安全实践。本文基于 Debian 12 / Ubuntu 24.04 环境编写,规则经过实际测试验证。
相关标签:nftables · iptables · Linux · 防火墙 · 网络安全 · 软路由 · OpenWrt
虾米生活分享

评论前必须登录!
注册