logo NodeSeekbeta

Docker 开了 UFW,容器端口为什么还能从公网访问?附自查方法

给自建服务做防火墙时,容易出现一个误判:UFW 只放行了 SSH、80、443,于是认为容器的管理端口也被挡住了。

但在 Linux Docker 常见的 bridge 端口发布场景里,容器流量经过的路径和宿主机普通进程不同。Docker 官方文档明确说明,发布端口的流量可能在进入 UFW 使用的 INPUT / OUTPUT 链之前就被转走。因此,ufw status 里的规则不能单独证明容器端口已经封住。官方说明

先看这一行端口映射

ports:
  - "8080:80"

没写宿主机地址时,默认会发布到所有宿主机地址。对于只需要宿主机上的 Nginx / Caddy 访问的后端,可以明确绑定回环地址:

ports:
  - "127.0.0.1:8080:80"

然后宿主机上的反向代理访问 http://127.0.0.1:8080。这个做法适用于普通 bridge 的 NAT 模式;host 网络、Swarm、容器地址直路由等场景需要分别检查。Docker 28.0.0 之前还存在同一二层网络可访问 localhost 发布端口的历史问题,旧版本不能只靠这一行判断隔离。端口发布文档

反向代理也在容器里,情况又不同

反代容器里的 127.0.0.1 指向反代容器自身。

如果反代和应用都跑在容器里,可以把它们接入同一个自定义 bridge 网络,让反代通过应用的服务名和容器端口连接,例如 http://app:80;应用不必再发布宿主机端口。数据库也一样,只供应用访问时,先考虑删除不必要的 ports。

同一网络里的容器能相互访问,所以也别把无关服务全部塞进一个公共网络。bridge 网络说明

自查可以按这个顺序来

先检查容器发布了什么:

docker ps --format 'table {{.Names}}	{{.Ports}}'

再对具体容器看完整映射,把 你的容器名 换成实际名称:

docker inspect 你的容器名 --format '{{json .NetworkSettings.Ports}}'

0.0.0.0、:: 的映射需要确认是否真有公网开放需求。ss -lntp 可以辅助检查宿主机监听,但有些端口转发由内核规则完成,不能把“没看到监听进程”直接当作“没有暴露”。

最后,从另一台外部机器测试自己的 VPS。Web 服务可以用下面的命令,示例地址需要换成实际地址:

curl --noproxy '*' --connect-timeout 3 --max-time 5 \
  http://203.0.113.10:8080/

如果 VPS 有公网 IPv6,也要单独测 IPv6:

curl --noproxy '*' -g --connect-timeout 3 --max-time 5 \
  'http://[2001:db8::10]:8080/'

只在 VPS 本机访问,验证不了公网侧的访问限制。外部测试失败也只代表当前测试路径不可达,还要结合绑定地址、安全组和防火墙规则确认。

确实需要公网发布时怎么办

使用 Docker 的 iptables 后端时,可以通过 DOCKER-USER 链添加容器转发过滤规则;这里的数据包已经经过 DNAT,匹配的端口要分清宿主机端口和容器端口。iptables 文档

Docker 原生 nftables 后端没有同样的 DOCKER-USER 链,需要按对应文档设置自己的表和链。系统里的 iptables 使用 nft 兼容层,也不等于 Docker 已切到原生 nftables 后端。nftables 文档

对几台自用小鸡来说,先减少不必要的端口发布,再验证剩余端口的访问范围,通常比直接套一份通用防火墙脚本容易维护。

想交流一下:大家的自建服务是宿主机反代,还是容器反代?有没有遇到过 IPv4 挡住了、IPv6 却仍能访问的情况?

  • 讲得很到位,Docker 绕过 UFW 这个坑几乎每个自建服务的佬都踩过。我的习惯是反代统一放宿主机(Nginx/Caddy),业务容器全部只绑 127.0.0.1:port 发布,这样哪怕 Docker 乱写 iptables 也只影响回环。补充一个 IPv6 的坑:Docker 默认开启 IPv6 时,ip6tables 的 FORWARD 链经常是全放行状态,楼主说的 v4 挡住、v6 仍能访问的情况我遇到过,解决办法是 compose 里加 --ipv6=false 或者手写 ip6tables 规则封掉。另外 ufw-docker 这个开源项目可以自动在 DOCKER-USER 链里同步 UFW 规则,懒人党的福音。

  • 这坑我也踩过

  • 我和二楼一样,自从知道 iptables拦不住 docker 规则后,单独在宿主机处理规则,docker全部指向 127.0.0.1

  • 安全组不放开 容器我不管

  • mark一下,有空试试

  • 楼主15min发了三个ai文章 xhj024

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有72640位seeker

🎉欢迎新用户🎉