在 Linux VPS 上执行 ufw deny 8080/tcp,并不一定能阻止 Docker 通过 -p 8080:80 发布的端口。Docker 会为端口映射创建转发和地址转换规则,数据包可能在到达 UFW 预期链路前就被转发到容器。这个现象不是所有发行版和网络模式都相同,排查时应以实际规则和外部连接结果为准。
先确认:端口是谁发布、从哪条路径进来
先不要改规则,记录容器、监听端口和 UFW 当前状态:
docker ps --format 'table {{.Names}} / {{.Ports}}'
sudo ss -lntup
sudo ufw status verbose
ip -br addr
ip route看到 0.0.0.0:8080->80/tcp,表示容器端口绑定在所有 IPv4 地址;如果是 127.0.0.1:8080,公网通常无法直接访问。IPv6 要单独看是否存在 [::]:8080 监听和安全组放行。
从宿主机检查 Docker 与防火墙规则
Docker 使用 iptables 还是 nftables 兼容层,取决于系统和 Docker 配置。分别查看过滤、转发和 NAT 规则,不要只看 ufw status:
sudo iptables -S
sudo iptables -t nat -S
sudo iptables -S DOCKER-USER
sudo iptables -S FORWARD
sudo nft list ruleset重点看 DOCKER-USER、FORWARD、DOCKER 和 DOCKER-ISOLATION 链。Docker 文档建议把面向容器的额外过滤放在 DOCKER-USER,因为该链位于 Docker 自己的转发规则之前;但接口名称、反向代理、IPv6 和云平台安全组仍可能改变最终路径。
先用绑定地址缩小暴露面
如果服务只供本机反代或运维访问,最稳妥的做法是不要绑定到公网:
docker run -d --name demo -p 127.0.0.1:8080:80 nginx:alpineCompose 中写成 127.0.0.1:8080:80 同样的含义。修改前先确认没有其他服务占用端口,并用 docker compose config 展开最终配置。只改 UFW 规则而继续把端口绑定到 0.0.0.0,会让后续维护依赖多层规则,容易遗漏 IPv6 或新网卡。
必须公网提供时,在 DOCKER-USER 做来源限制
若端口确实要公网访问,应先明确允许的来源网段,再在 DOCKER-USER 链中限制。下面示例只允许一个办公网段访问宿主机的 8080 端口;执行前请替换为实际网段,并确认已有远程管理白名单:
sudo iptables -I DOCKER-USER 1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
sudo iptables -I DOCKER-USER 2 -p tcp -s 203.0.113.0/24 -m conntrack --ctorigdstport 8080 -j ACCEPT
sudo iptables -I DOCKER-USER 3 -p tcp -m conntrack --ctorigdstport 8080 -j DROP
sudo iptables -S DOCKER-USER流量进入 DOCKER-USER 时通常已经完成 DNAT,直接写 --dport 8080 可能匹配到的是容器端口而不是宿主机原始端口。上例用 conntrack 的 --ctorigdstport 匹配最初访问的 8080;也要结合 iptables -t nat -S DOCKER 核对实际转换。对多端口、反向代理和跨网卡转发,可在确认公网网卡名称后增加入站接口条件,并先在控制台保留回滚入口。203.0.113.0/24 是文档示例网段,不是可直接使用的办公地址;conntrack 原始目标匹配还会增加规则处理开销,应只用于必要流量。
如果系统以 nftables 为主,应使用对应的 nft 规则或确认 iptables-nft 兼容层实际生效;不要同时维护两套互不相同的规则并把其中一套当成最终策略。
别漏掉云安全组和 IPv6
VPS 的云安全组在宿主机之外,UFW 和 Docker 规则无法替代它。公网验收应分别从 IPv4 和 IPv6 网络测试:
nc -vz -w 3 SERVER_IPV4 8080
curl -4 -I --max-time 5 http://SERVER_IPV4:8080/
curl -6 -I --max-time 5 http://[SERVER_IPV6]:8080/从另一条网络执行测试更有意义;在服务器本机访问 127.0.0.1 只能证明本地路径。若 IPv4 被拒绝而 IPv6 可访问,检查 ufw status、ip6tables、云安全组 IPv6 规则和容器是否发布了 IPv6。
规则变更后的验收与回滚
- 用
docker ps、ss -lntup确认映射和监听地址符合设计。 - 从允许和不允许的来源各测试一次,记录连接结果和时间。
- 查看计数器:
sudo iptables -vnL DOCKER-USER,确认流量确实命中预期规则。 - 检查重启 Docker 或服务器后规则是否由声明式配置恢复,避免只在当前运行时有效。
- 保留原规则导出和控制台救援方式,远程操作不要在未验证 SSH 白名单时清空防火墙。
如果表现为“服务已启动但公网端口不通”,还要沿监听地址、系统防火墙、安全组、公网地址和路由逐层检查,可参考VPS端口不通的分层排查方法。如果问题只发生在重启之后,再检查 Docker 重启策略和依赖顺序,而不是反复开放端口。
常见问题
UFW 显示 deny,为什么 Docker 端口仍能访问?
Docker 的转发和 NAT 规则可能改变数据包经过的链路。需要同时检查 DOCKER-USER、FORWARD、NAT、云安全组以及外部测试结果。
把 Docker 的 iptables 选项关闭就能解决吗?
不建议直接关闭。可能导致端口映射、出站访问或容器网络失效;应先理解现有网络设计,再用绑定地址或 DOCKER-USER 过滤实现最小暴露。
只绑定 127.0.0.1 后,反向代理还能访问吗?
如果反向代理运行在宿主机上,可以通过 127.0.0.1 访问;若反向代理在另一个容器中,应改用同一 Docker 网络和服务名,而不是假设容器内的 127.0.0.1 指向宿主机。
iptables 规则重启后消失怎么办?
将策略写入发行版支持的持久化机制或基础设施配置,并在重启 Docker、重启 VPS 后重新做 IPv4/IPv6 外部验收。






