
核心要点(TL;DR)
- 安全组先于主机防火墙生效,主机防火墙先于 Docker 规则,顺序错位是端口不通的主因。
- ufw 只是 iptables 前端,两者混用会互相覆盖,排查应先看 iptables-save 真实规则。
- Docker 发布端口会绕过 ufw,放行必须在 DOCKER-USER 链或安全组完成。
- 规则持久化缺失会导致重启后失效,改完必须验证并保存。
不少运维在云服务器上放行端口时都遇到过这种场景:安全组明明加了 80 端口,ufw allow 80 也执行了,浏览器却依旧超时。反复重启服务、重装系统都无效,最后发现是安全组、ufw、iptables 与 Docker 规则的生效顺序被搞混了。本文按「四层链路」拆解配置顺序,给出可直接复制的排查命令与修复步骤,帮你一次定位问题。
一、先搞清四层链路:谁先谁后
数据包进入云服务器,会依次经过以下关卡,任何一层拦截都会表现为「端口不通」:
| 层级 | 生效位置 | 典型工具 | 优先级 |
|---|---|---|---|
| 云安全组 | 云平台虚拟网络层 | 控制台/OpenAPI | 最先,包未到主机即被丢 |
| 主机防火墙 | 内核 netfilter INPUT 链 | ufw / iptables | 其次 |
| Docker 规则 | nat 表与 FORWARD 链 | docker-proxy / DOCKER-USER | 发布端口时绕过 INPUT |
| 服务监听 | 应用进程 | nginx / sshd | 最后,监听地址决定可达性 |
关键结论:安全组先于主机防火墙生效,主机防火墙先于 Docker 规则。顺序错位时,你在错误的一层反复放行,自然无效。
二、常见踩坑:规则顺序错位的四种表现
- ufw 与 iptables 混用:手工
iptables -A的规则在ufw reload后被清空,放行「自动消失」。 - DROP 规则前置:默认策略为 DROP 时,后追加的 ACCEPT 永远不会命中,必须用
-I插到链首。 - Docker 绕过 ufw:容器发布端口走 FORWARD 链,ufw 的 INPUT 规则形同虚设,安全边界被悄悄打开。
- 规则未持久化:只改了运行时规则,重启后回滚,表现为「昨天还好好的」。
三、分步排查:四条命令逐层收敛
第 1 步:确认服务监听地址
ss -lntp | grep -E ':80|:443'
若显示 127.0.0.1:80,说明服务只监听本地,外部必然不通,问题不在防火墙。
第 2 步:查看主机防火墙真实规则
ufw status verbose iptables-save -t filter | head -50
注意默认策略与规则顺序,DROP 在前时后续 ACCEPT 无效。
第 3 步:确认包是否到达主机
tcpdump -i eth0 -nn port 80 -c 20
完全无 SYN 到达,说明被安全组或云网络拦截;有 SYN 无 SYN-ACK,说明主机防火墙或服务未响应。
第 4 步:检查 Docker 链
iptables -L DOCKER-USER -n -v iptables -t nat -L DOCKER -n -v
观察命中计数是否增长,确认容器端口是否被 DOCKER-USER 拦截。
四、分步修复:按正确顺序重配
- 先定安全组:在云控制台只放行必要端口,来源限定业务 IP 段,避免 0.0.0.0/0 全开。
- 再配主机防火墙:二选一。用 ufw 时执行
ufw default deny incoming后ufw allow 22/tcp、ufw allow 80,443/tcp;用 iptables 时用-I INPUT插入放行规则,避免追加到 DROP 之后。 - 处理 Docker:在 DOCKER-USER 链放行,例如
iptables -I DOCKER-USER -p tcp --dport 8080 -s 10.0.0.0/8 -j ACCEPT,并在链尾显式 DROP 非预期流量。 - 持久化:Debian/Ubuntu 执行
netfilter-persistent save;CentOS 执行iptables-save > /etc/sysconfig/iptables,随后重启验证。
防护建议:安全组与主机防火墙应保持「最小放行 + 来源收敛」的一致策略。若使用 AegisX,可将云安全组规则与主机防火墙基线纳入统一核查,减少两侧策略漂移带来的顺序踩坑。
五、上线检查清单
- 安全组仅放行必要端口,来源非 0.0.0.0/0。
- ufw 与 iptables 不混用,默认策略为 DROP 时放行规则置于链首。
- Docker 端口在 DOCKER-USER 链或安全组层面限制。
- 规则已持久化,重启后
iptables-save输出一致。 - 用 tcpdump 与
iptables -L -n -v计数双重验证。
行动建议:把「安全组→主机防火墙→Docker 链→服务监听」固化为变更后的固定排查顺序,每次改规则后立即执行清单验证并保存,能避免绝大多数「放行了却不生效」的反复踩坑。
常见问题(FAQ)
安全组已经放行 80 端口,为什么网站还是打不开?
结论:问题多半在主机防火墙或服务监听,而非安全组。先在本机执行 ss -lntp | grep 80 确认服务确实监听在 0.0.0.0 而非 127.0.0.1;再执行 ufw status verbose 与 iptables-save -t filter 查看是否有 DROP 规则;若使用 Docker,检查 DOCKER-USER 链是否拦截。逐层排除后即可定位。
ufw 和 iptables 可以同时用吗?会不会冲突?
结论:可以共存但极易互相覆盖,不建议混用。ufw 本质是 iptables 的前端,它通过自己的链管理规则,你手工添加的 iptables 规则在 ufw reload 或重启后可能被清空。建议二选一:Ubuntu 系用 ufw 管理常规端口,复杂需求直接写 iptables 并配合 iptables-persistent 保存,避免两套规则交叉。
Docker 容器端口放行了 ufw 还是不通,怎么处理?
结论:Docker 发布端口时会插入自己的 NAT 与 FORWARD 规则,绕过 ufw 的 INPUT 链。正确做法是在 DOCKER-USER 链中加放行或限制规则,例如 iptables -I DOCKER-USER -p tcp --dport 8080 -j ACCEPT,也可在云安全组层面直接限制来源 IP。修改后用 iptables -L DOCKER-USER -n -v 核对命中计数。
iptables 规则重启后就没了,如何持久化?
结论:需要显式保存并配置开机恢复。Debian/Ubuntu 安装 iptables-persistent 后执行 netfilter-persistent save;CentOS 用 service iptables save 或 iptables-save > /etc/sysconfig/iptables。保存后重启验证 iptables-save 输出是否一致,避免只改了运行时规则。
如何快速判断是安全组还是主机防火墙拦截?
结论:用对端抓包与云监控对比即可分离。在服务器执行 tcpdump -i eth0 port 80 观察是否有 SYN 到达:完全无包说明被安全组或云网络拦截;有 SYN 无 SYN-ACK 说明主机防火墙或服务未响应。再结合 iptables -L -n -v 的计数增长确认具体链路。