Skip to content

15|iptables 防火墙

服务起了、端口也监听了,从外部却访问不了——一查是防火墙把端口挡了。Linux 上做主机侧包过滤的,老一点的是 iptables,新的是 nftables。但 iptables 仍然广泛应用——老系统、容器网络(Kubernetes 的 kube-proxy 就生成大量 iptables 规则)、各种技术文档都依赖它。

本篇讲 iptables 在 Linux 网络栈里的位置、表/链/规则的核心模型,再给生产环境的标准规则模板、远程改防火墙的保命操作,以及 NAT 等进阶用法。

一、netfilter、iptables、firewalld、nftables 的关系

这几个名字经常被混用,先一次性理清:

  • netfilter — Linux 内核中处理数据包的框架,提供"钩子点"让规则能在数据包经过网络栈时被检查
  • iptables — 用户态工具,把规则写入 netfilter,操作老的 xtables 表/链模型
  • nftables — netfilter 的新一代用户态工具(2014 起逐步取代 iptables),用全新的表/链结构,效率更高
  • firewalld — 更高层的防火墙管理服务,底层可以使用 iptables 或 nftables 作为后端
  • ufw — Ubuntu 的简化防火墙前端,底层也是 iptables

关键概念:你敲的 iptables 命令只是把规则配置写入内核 netfilter,真正在数据包流转时做匹配的是内核。这解释了几个常见现象:

  • iptables 规则改完立即生效(内核运行时变更,无需重启)
  • 重启系统后规则全部丢失(规则在内存中,不在磁盘),必须显式 iptables-save 持久化
  • iptables -V 查看的是用户态工具版本,内核 netfilter 的能力可能更新

当前主流发行版的默认状态

发行版默认前端实际后端
CentOS 7 / RHEL 7firewalld 或 iptables 服务iptables (xtables)
RHEL 8+ / Rocky 8+firewalldnftables(向后兼容 iptables 命令)
Ubuntu 18.04iptables / ufwiptables (xtables)
Ubuntu 20.04+iptables / ufw / nftablesnftables(默认 iptables 命令实际是 iptables-nft)
Debian 11+nftablesnftables

RHEL 8+ 和 Ubuntu 20.04+ 上,即使你敲的是 iptables 命令,实际操作的可能是 nftables——这是兼容层 iptables-nft 的作用。验证:

bash
$ iptables -V
iptables v1.8.7 (nf_tables)
# 括号里看到 nf_tables 表示后端实际是 nftables
# 看到 legacy 表示是经典 xtables 后端

混用 iptables-legacy 和 iptables-nft 会出现"规则看起来加上了但不生效"——iptables-legacy -Liptables-nft -L 看的是两套独立规则。统一用一种,生产环境选定后写入文档明确约束。

二、确认本机由谁管理防火墙

任何修改之前,必须先确认本机当前由哪个工具在管:

bash
# 看 iptables 版本和后端
iptables -V

# 看 firewalld 是否运行(RHEL 系)
systemctl status firewalld

# 看 ufw 是否启用(Ubuntu)
ufw status

# 直接看当前 iptables 规则
iptables -L -n -v
iptables -t nat -L -n -v

多个工具同时启用会互相覆盖。常见冲突场景:

  • 服务器装了 firewalld(开机自启),你手动 iptables -A 加的规则,firewalld reload 时被清掉
  • Docker 启动时会自动添加 iptables 规则(管理容器网络),如果直接 iptables -F 清空规则,Docker 网络就坏了
  • Kubernetes 节点上 kube-proxy 会大量生成 iptables 规则,人工添加的规则可能被冲掉

生产环境的最佳实践:整个团队约定使用一套工具(iptables / firewalld / nftables 三选一),不允许混用。在 init 阶段就明确启用其中一个、禁用其他:

bash
# 选择 iptables 直接管理,禁用 firewalld
systemctl stop firewalld
systemctl disable firewalld
systemctl mask firewalld          # mask 表示彻底禁用,无法被其他服务依赖触发启动

systemctl enable iptables         # RHEL 7
# 或 RHEL 8+:
yum install iptables-services -y
systemctl enable iptables ip6tables

三、表、链、规则的三层模型

iptables 的规则组织成三个层次:(按功能分类)、(报文经过内核网络栈的检查点)、规则(匹配条件 + 动作)。

四张表

用途使用频率
filter包过滤(放行/阻止),默认表极高,90% 的规则都在这
nat地址转换(SNAT、DNAT、MASQUERADE)高,网关、端口转发场景
mangle修改包头字段(TOS、TTL、MSS、mark)低,QoS、流量整形场景
raw在连接跟踪之前处理低,排除某些流量不做 conntrack

操作其他表必须 -t <表名>,不指定默认是 filter:

bash
iptables -L                       # 等同于 iptables -t filter -L
iptables -t nat -L                 # 看 nat 表
iptables -t mangle -L              # 看 mangle 表

五条内置链

链对应报文经过内核网络栈的不同位置:

触发时机
PREROUTING报文刚到网卡,还未做路由决策
INPUT路由决策后,目标是本机
FORWARD路由决策后,需要转发到别的机器(本机作为网关)
OUTPUT本机进程发出的报文
POSTROUTING报文即将离开网卡

报文经过哪些链取决于方向

流量方向经过的链
外部 → 本机服务PREROUTING → INPUT
本机 → 外部OUTPUT → POSTROUTING
外部 → 本机转发 → 外部PREROUTING → FORWARD → POSTROUTING

排查端口不通的第一步:确定流量方向,据此选择查哪条链

  • 别人访问本机服务不通 → 查 INPUT(filter 表)
  • 本机连不上外部 → 查 OUTPUT(filter 表)
  • 本机作为网关转发不通 → 查 FORWARD(filter 表)
  • 端口转发不通 → 查 PREROUTING(nat 表)+ FORWARD(filter 表)

四、规则的查看与基本结构

查看命令

bash
iptables -L -n -v                       # filter 表,所有链
iptables -L INPUT -n -v --line-numbers  # 看 INPUT 链,带行号
iptables -S                              # 输出格式接近命令本身,适合复制粘贴
iptables -t nat -L -n -v                 # NAT 表
iptables -t nat -L PREROUTING -n -v      # NAT 表的 PREROUTING 链

参数含义:-L list、-n 不解析名称(快很多)、-v 显示计数器(packets / bytes)、-S 以规则定义形式输出。

计数器:排查规则是否生效的关键

-v 输出里每条规则前的 pkts / bytes 是该规则匹配到的累计包数和字节数。计数器持续为 0 说明这条规则从未被命中——可能是因为:

  • 流量方向理解错了(在错误的链里加规则)
  • 表选错了(应在 nat 表里加但写到了 filter 表)
  • 规则顺序错了,被前面的规则提前匹配掉
  • 上游网络就把包丢了,根本没到本机

排查"规则改了但没效果"的标准动作:先看计数器,不要凭感觉调规则。

bash
# 清零计数器,然后产生测试流量,再看哪些规则被命中
iptables -Z                              # 清零 filter 表所有计数器
iptables -Z INPUT 3                      # 清零 INPUT 第 3 条
# ... 产生测试流量 ...
iptables -L INPUT -n -v

规则的基本语法

bash
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/24 -j ACCEPT

逐段:

  • -A INPUT — append 到 INPUT 链末尾(-I INPUT 1 表示插入到第 1 条位置)
  • -p tcp — 匹配 TCP 协议
  • --dport 22 — 目的端口 22
  • -s 10.0.0.0/24 — 源 IP 在该网段
  • -j ACCEPT — 目标(jump 到的 target)是 ACCEPT

常用匹配条件:

条件含义
-p tcp/udp/icmp协议
--dport N / --sport N目的端口 / 源端口
--dports N,M,K多端口(需要 -m multiport)
-s <CIDR> / -d <CIDR>源 IP / 目的 IP
-i <网卡> / -o <网卡>入站网卡 / 出站网卡
-m conntrack --ctstate ...连接状态匹配
-m set --match-set <name>ipset 集合匹配
-m time --timestart 09:00 --timestop 18:00时间窗口匹配

常用动作(target):

动作行为客户端看到
ACCEPT放行正常通信
DROP静默丢弃连接超时(几十秒)
REJECT拒绝并回复 ICMP/RST立即 Connection refused / unreachable
LOG记录到 syslog,不阻断匹配继续客户端无感知
RETURN从当前链返回到调用者内部跳转,无外部行为
<自定义chain名>跳转到自定义链内部跳转

DROP vs REJECT 的选择

场景推荐原因
公网入口DROP不回复任何信息,扫描器无法判断端口是否存在(不暴露服务列表)
内网排错环境REJECT失败立即返回,不至于让应用等到超时,排查效率更高
阻止恶意 IPDROP不消耗本机资源回包
限制本机用户访问某服务REJECT --reject-with icmp-port-unreachable给应用准确的错误,避免应用日志写满超时记录

五、最小可用规则集模板

一个生产可用的最小规则集,放行 SSH、Web 服务,禁止其他入站:

bash
#!/bin/bash
# 标准基础规则集

# 1. 清空当前规则(只在初始配置时,远程操作前必须备份当前规则!)
iptables -F INPUT
iptables -F OUTPUT
iptables -F FORWARD

# 2. 默认策略先设 ACCEPT,所有规则配置完再改 DROP
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT

# 3. 放行已建立和相关的连接(关键!没有这条本机访问外网也会断)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 4. 放行本机回环(很多本地服务依赖 127.0.0.1 通信)
iptables -A INPUT -i lo -j ACCEPT

# 5. 放行 ICMP(可选,生产可只放行 echo-reply)
iptables -A INPUT -p icmp -j ACCEPT

# 6. 放行 SSH(限制源 IP 更安全)
iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j ACCEPT

# 7. 放行业务端口
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 8. 记录被丢弃的包(便于排查,但限速避免日志爆炸)
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables-dropped: " --log-level 4

# 9. 默认策略改为 DROP(必须最后做)
iptables -P INPUT DROP

# 10. 持久化
iptables-save > /etc/sysconfig/iptables    # RHEL
# 或 iptables-save > /etc/iptables/rules.v4   # Debian/Ubuntu

几个关键约束

约束 1:ESTABLISHED,RELATED 必须在 INPUT 链最前面

如果默认策略是 DROP,没有这条规则,本机主动发起的连接(浏览器、curl、yum、git)的返回包会被丢弃——本机彻底不能访问外网。这是新手最容易踩的坑。

约束 2:默认策略 DROP 必须最后设置

bash
# 错误顺序:先 DROP 再添加 ACCEPT 规则
iptables -P INPUT DROP                    # SSH 立刻断
iptables -A INPUT -p tcp --dport 22 -j ACCEPT   # 已经断了,加这条也没用

# 正确顺序:先确保所有放行规则到位,最后改默认策略
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# ... 其他规则 ...
iptables -P INPUT DROP

约束 3:lo 必须放行

很多本地服务通过 127.0.0.1 通信(数据库 socket、本地 RPC、监控指标采集),没有这条规则,这些通信全部失败。

六、远程改防火墙的保命流程

远程通过 SSH 改防火墙规则是和远程改网络配置同级的高风险操作。一条 iptables -P INPUT DROP 或一条错误的拒绝规则,立刻把自己关在外面。

第 1 步:备份当前规则

任何修改前,先把当前规则保存一份:

bash
iptables-save > /tmp/iptables-backup-$(date +%Y%m%d-%H%M%S).rules
iptables -t nat -L -n -v > /tmp/iptables-nat-backup-$(date +%Y%m%d-%H%M%S).log

第 2 步:开 tmux 保持会话

bash
tmux new -s fw

如果 SSH 因防火墙错误断开,tmux 会话仍在后台运行,自动恢复脚本能继续执行。

第 3 步:准备定时回滚脚本

这是最重要的保命手段——用 at 设置 10 分钟后自动恢复原规则,如果 10 分钟内确认配置 OK,取消这个任务:

bash
# 准备 10 分钟后自动恢复
echo "iptables-restore < /tmp/iptables-backup-$(date +%Y%m%d-%H%M%S).rules" \
    | at now + 10 minutes
# atq 看到任务编号,例如 7

# 改规则
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# ... 其他规则 ...
iptables -P INPUT DROP

# 验证新规则:从另一台机器尝试 SSH 连接
# 验证通过 → 取消自动恢复
atrm 7

# 持久化
iptables-save > /etc/sysconfig/iptables

10 分钟内不取消,系统会自动把规则恢复到操作前的状态。即使 SSH 完全断开,等够 10 分钟就能重新登录。

简化版本(无 at 时):

bash
# 5 分钟后无条件恢复(除非这个进程被 kill)
nohup bash -c "sleep 300 && iptables-restore < /tmp/iptables-backup.rules" &
FALLBACK_PID=$!

# 改规则、测试...

# 验证 OK 后取消
kill $FALLBACK_PID

第 4 步:不在默认策略 DROP 状态下做编辑

远程操作时,保持默认策略 ACCEPT,通过具体的 DROP 规则实现限制——这样即使中间步骤漏写,SSH 也不会立刻断。所有规则添加完、验证完之后,最后一步才改默认策略:

bash
# 推荐流程
iptables -P INPUT ACCEPT                          # 保持宽松状态
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# ... 全部规则添加完毕 ...
iptables -A INPUT -j DROP                          # 最后一条:DROP 所有未匹配
# 不改 -P INPUT,保持 ACCEPT。最后那条 -A INPUT -j DROP 起到同样效果
# 但更安全——这是一条普通规则,而不是默认策略

如果发现某条规则写错了,可以用 -D 删除那条规则,而不是改默认策略——一切错误都可以局部修复,不会"一键自杀"。

七、连接状态跟踪 conntrack

iptables 通过连接跟踪(conntrack)识别一个包属于哪个连接、处于什么状态。

五种连接状态

状态含义
NEW新连接的第一个包
ESTABLISHED属于已经建立的连接
RELATED与已有连接相关(如 FTP 数据通道、ICMP 错误响应)
INVALID无法归类的异常包
UNTRACKED显式标记为不跟踪(raw 表 NOTRACK target)

ESTABLISHED,RELATED 是几乎所有 INPUT 链放行规则的第一条:

bash
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

老写法是 -m state --state ...,新写法是 -m conntrack --ctstate ...,功能等价,新规则统一用 conntrack

conntrack 表本身的容量限制

conntrack 跟踪每个连接占用一个条目,容量上限 net.netfilter.nf_conntrack_max。具体问题和处理见 第 14 讲 网络诊断与排错 第八节"conntrack 表满"。

看 conntrack 跟踪的当前连接

bash
# 装 conntrack-tools
yum install conntrack-tools -y
apt install conntrack -y

# 看当前所有跟踪的连接
conntrack -L

# 看某个具体连接
conntrack -L -p tcp --dport 80

# 删除某个跟踪条目(用于强制中断某个连接)
conntrack -D --orig-src 1.2.3.4

八、NAT:SNAT、MASQUERADE、DNAT

NAT 修改包的源地址或目的地址,典型场景:

场景链 + 表target
内网共享一个公网 IP 上网(NAT 网关)-t nat POSTROUTINGMASQUERADESNAT
外部访问到内网某机器(端口映射)-t nat PREROUTINGDNAT
修改本机对外访问的源 IP-t nat POSTROUTINGSNAT

MASQUERADE:动态源 IP 转换

MASQUERADE 是 SNAT 的特殊形式,自动使用出口网卡当前的 IP 作为转换后的源地址。适合出口 IP 可能变化的场景(动态 IP、ADSL):

bash
# 让 10.0.0.0/24 网段的流量从 eth0 出去时,源 IP 改为 eth0 的 IP
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE

SNAT:固定源 IP 转换

如果出口 IP 已知且固定,SNAT 比 MASQUERADE 性能稍好(不需要每个包都查询接口 IP):

bash
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j SNAT --to-source 203.0.113.1

DNAT:端口转发

把外部访问本机 8080 的流量,转发到内网 10.0.0.10:80:

bash
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.10:80

启用 IP 转发

做 NAT 或转发,必须启用 IP 转发功能:

bash
# 临时启用
sysctl -w net.ipv4.ip_forward=1

# 持久化
echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-ip-forward.conf
sysctl --system

漏掉这一步是 NAT 配置最常见的失败原因——iptables 规则配得完全正确,但因为 ip_forward=0,内核不转发包,表现为"规则计数器是 0,完全没生效"。

DNAT 后,FORWARD 链也要放行

DNAT 在 PREROUTING 改写目的地后,包还要经过 FORWARD 链才能转发出去。filter 表 FORWARD 链如果默认 DROP,DNAT 仍然不工作:

bash
# DNAT
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.10:80

# 同时在 filter FORWARD 放行(关键,否则被默认 DROP 拦掉)
iptables -A FORWARD -p tcp -d 10.0.0.10 --dport 80 -m conntrack --ctstate NEW -j ACCEPT

九、自定义 chain:让规则可维护

当 INPUT 链规则超过几十条,管理就很费劲。自定义 chain 让规则按业务/逻辑分组,主链只做分发:

bash
# 1. 创建自定义 chain
iptables -N WEB-INPUT
iptables -N SSH-INPUT
iptables -N ADMIN-INPUT

# 2. 主链按目标端口分发到对应 chain
iptables -A INPUT -p tcp --dport 80 -j WEB-INPUT
iptables -A INPUT -p tcp --dport 443 -j WEB-INPUT
iptables -A INPUT -p tcp --dport 22 -j SSH-INPUT
iptables -A INPUT -p tcp -m multiport --dports 3306,5432,6379 -j ADMIN-INPUT

# 3. 各业务 chain 内部写具体规则
# Web 服务对所有人开放
iptables -A WEB-INPUT -j ACCEPT

# SSH 只允许内网
iptables -A SSH-INPUT -s 10.0.0.0/8 -j ACCEPT
iptables -A SSH-INPUT -j LOG --log-prefix "ssh-denied: "
iptables -A SSH-INPUT -j DROP

# 数据库类只允许应用服务器网段
iptables -A ADMIN-INPUT -s 10.1.0.0/16 -j ACCEPT
iptables -A ADMIN-INPUT -j DROP

# 4. 删除整个自定义 chain
iptables -F WEB-INPUT     # 先清空
iptables -X WEB-INPUT     # 再删除

好处:

  • 主 INPUT 链只有十几条分发规则,一眼看清结构
  • 调整 Web 访问策略,只需在 WEB-INPUT 中改,不影响其他业务
  • 出问题时可以独立看某个 chain 的计数器,定位精准

十、ipset:大量 IP 的高性能匹配

需要根据几千上万个 IP 做匹配(黑名单、白名单、地理 IP 限制)时,不要写几千条 iptables 规则——每个包要逐条匹配,性能急剧下降。

ipset 把 IP 集合存储在内核哈希表里,iptables 用一条规则就能匹配整个集合,O(1) 查找复杂度。

bash
# 装 ipset
yum install ipset -y
apt install ipset -y

# 创建一个 IP 集合
ipset create blacklist hash:ip maxelem 1000000

# 加 IP(可批量从文件加)
ipset add blacklist 1.2.3.4
ipset add blacklist 5.6.7.8
while read ip; do ipset add blacklist "$ip"; done < blacklist.txt

# iptables 用一条规则匹配整个集合
iptables -I INPUT 1 -m set --match-set blacklist src -j DROP

# 查看集合内容
ipset list blacklist

# 删除 IP
ipset del blacklist 1.2.3.4

# 持久化(集合本身要保存)
ipset save > /etc/ipset.conf
# 恢复
ipset restore < /etc/ipset.conf

集合类型选择

类型存储用途
hash:ip单个 IPIP 黑/白名单
hash:netCIDR 网段网段黑/白名单(国家 IP 段)
hash:ip,portIP + 端口限制某 IP 访问特定端口
hash:macMAC 地址MAC 过滤

地理 IP 限制的标准模板:

bash
# 只允许中国大陆 IP 访问 22 端口
ipset create cn-cidr hash:net maxelem 100000
# 从 GeoIP 数据导入中国 IP 段
while read cidr; do ipset add cn-cidr "$cidr"; done < cn-cidr-list.txt

iptables -A INPUT -p tcp --dport 22 -m set --match-set cn-cidr src -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j DROP

性能数据:同样阻止 10 万个 IP,纯 iptables 规则会让每个包平均匹配 5 万条规则,CPU 直接吃满;改用 ipset,匹配复杂度从 O(N) 降到 O(1),CPU 几乎无影响。

十一、LOG target:排查规则的关键

LOG target 把匹配到的包记录到 syslog,不阻断,继续匹配后面的规则。这是排查"我的规则到底匹配了什么"的核心工具:

bash
# 在 DROP 之前加一条 LOG,看到底什么包被丢了
iptables -A INPUT -j LOG --log-prefix "iptables-dropped: " --log-level 4
iptables -A INPUT -j DROP

# 日志查看
journalctl -k -f | grep "iptables-dropped"
# 或
tail -f /var/log/kern.log | grep "iptables-dropped"

LOG 必须限速,否则会撑爆日志

恶意扫描或者突发流量下,LOG 规则一秒钟可能产生几千条日志,瞬间把 /var/log 占满。生产环境的 LOG 规则必须配 -m limit 限速:

bash
iptables -A INPUT -m limit --limit 5/min --limit-burst 10 \
    -j LOG --log-prefix "iptables-dropped: " --log-level 4

--limit 5/min 表示每分钟最多记录 5 条,--limit-burst 10 是初始突发额度。这样既能看到代表性的丢包样本,又不会撑爆磁盘。

十二、持久化:重启不丢规则

iptables 规则存在内核内存,重启后丢失。必须显式保存到配置文件。

RHEL / CentOS / Rocky

RHEL 7:

bash
iptables-save > /etc/sysconfig/iptables
systemctl enable iptables

RHEL 8+:

bash
yum install iptables-services -y
iptables-save > /etc/sysconfig/iptables
systemctl enable iptables ip6tables

或者用 firewalld(推荐):

bash
firewall-cmd --permanent --add-port=80/tcp
firewall-cmd --reload
# firewalld 自动持久化,无需额外保存

Debian / Ubuntu

bash
apt install iptables-persistent -y
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
systemctl enable netfilter-persistent

配置文件作为版本管理

iptables-save 输出的格式是文本,可以直接放进 Git 做版本管理。比"手工执行命令"更可靠:

bash
# 提交当前规则到 Git
iptables-save > firewall-rules-$(hostname).conf
git add firewall-rules-$(hostname).conf
git commit -m "update firewall: allow port 8080 for app rollout"

# 部署时
iptables-restore < firewall-rules-$(hostname).conf

十三、向 nftables 迁移

iptables 在新发行版上正在被 nftables 替代。nftables 的优势:

  • 单一工具替代 iptables/ip6tables/arptables/ebtables 四个
  • 规则结构更清晰,支持原生集合、字典、多维表达式
  • 性能更好(尤其规则数量大时)
  • 原子规则更新(整批替换,不会出现中间状态)

命令对照

iptablesnftables
iptables -Lnft list ruleset
iptables -A INPUT -p tcp --dport 22 -j ACCEPTnft add rule inet filter input tcp dport 22 accept
iptables-save > filenft list ruleset > file
iptables-restore < filenft -f file

iptables-translate:自动转换

iptables-translate 命令(随 nftables 提供)可以把现有 iptables 命令翻译成 nftables 语法,辅助迁移:

bash
iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
# 输出:
# nft 'add rule ip filter INPUT tcp dport 22 counter accept'

何时迁移

  • 现在:RHEL 8+、Debian 11+、Ubuntu 22.04+ 上的新项目可以直接用 nftables
  • 过渡期:存量 iptables 规则在 RHEL 8+ 上通过 iptables-nft 兼容层工作,无需立即迁移
  • 不要混用:在同一台机器上不要同时用 iptables-legacy 和 nftables(包括 iptables-nft),会出现"看不见对方规则"的现象

十四、易踩的陷阱速查

现象根因处理
-P INPUT DROP 后 SSH 立刻断默认策略改 DROP 时,放行 SSH 规则未生效远程修改用本讲第六节的保命流程
本机连不上外网,但 INPUT 链里放行了出站INPUT 链没有 ESTABLISHED,RELATED 规则,返回包被丢第一条加 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
规则改完没生效,计数器始终 0流量方向错(查错链)或表错(规则在 filter 但应在 nat)看计数器、确认流量方向、对照表/链选择
DNAT 规则正确但流量不通net.ipv4.ip_forward = 0 或 FORWARD 链 DROP启用 ip_forward 并放行 FORWARD
iptables 命令看不到 Docker/K8s 规则RHEL 8+ 上 iptables -V 显示 legacy,但 Docker 用 nf_tables统一使用 iptables-nft,或全部走 nftables
iptables -F 清空后 Docker 网络坏Docker 规则被清掉不要无脑 -F,重启 Docker 重建规则:systemctl restart docker
LOG 规则后日志爆磁盘没加 -m limit 限速LOG 规则必须配 --limit 5/min 这样的限速
重启后规则丢失没持久化改完立刻 iptables-save 持久化
几千条规则后 CPU 高包按规则顺序逐条匹配,O(N) 复杂度大量 IP 匹配改用 ipset
临时排查时加的规则忘了删没有规则生命周期管理临时规则在注释里写来源和到期时间,用 iptables -A INPUT ... -m comment --comment "tempXXX" 标记