跳到主要内容

Docker 端口映射与访问范围控制

很多“为什么别人能访问 / 为什么别人访问不到”的问题,本质都在这里:你到底把容器端口发布到了宿主机的哪个地址、哪个端口。

先记住 -p 的格式

最常见写法:

docker run -p [宿主机IP:]宿主机端口:容器端口 IMAGE

例如:

docker run -d --name web -p 8080:80 nginx:stable

意思是:

  • 容器内部服务监听 80
  • 宿主机通过 8080 对外提供访问

4 种最常见的发布方式

1. -p 8080:80

docker run -d --name web -p 8080:80 nginx:stable

这是最常见的写法,也最容易让人忽略默认暴露范围。它通常意味着宿主机在所有可用网络接口上监听这个端口。

如果宿主机本身能被局域网或公网访问,这个服务通常也就一起暴露出去了。

2. -p 127.0.0.1:8080:80

docker run -d --name web -p 127.0.0.1:8080:80 nginx:stable

这表示只绑定到本机回环地址。

适合下面这些情况:

  • 只想让本机程序访问
  • 准备用 Nginx、Caddy 或其他反向代理转发
  • 准备用 SSH 隧道、VS Code Port Forward、frp 之类方式间接访问

如果只是个人服务或临时调试,我更推荐优先从这个写法开始。

3. -p 0.0.0.0:8080:80

docker run -d --name web -p 0.0.0.0:8080:80 nginx:stable

含义非常直接:绑定宿主机所有 IPv4 地址。

如果你就是要让别的机器访问它,这种写法最清楚。但别忘了,开放到 0.0.0.0 不等于一定能从公网访问,还要同时看:

  • 云服务器安全组
  • 宿主机防火墙
  • 上游网络策略

4. -p 192.168.1.10:8080:80

docker run -d --name web -p 192.168.1.10:8080:80 nginx:stable

适合多网卡机器或既有公网 IP 又有私网 IP 的机器。

例如一台服务器同时有:

  • 公网 IP:203.0.113.10
  • 私网 IP:10.0.0.10

那么你可以显式决定服务只给哪一个地址提供访问。

不要把 EXPOSE-p 混为一谈

Dockerfile 里的 EXPOSE 80 只是镜像元信息,不等于真的把宿主机端口打开。

真正让宿主机可以访问的是:

docker run -p ...

如果你只写了 EXPOSE,但运行时没写 -p,宿主机通常仍然访问不到这个服务。

怎么确认当前到底映射到了哪里

先看容器本身:

docker ps
docker port web

再看宿主机监听情况:

ss -lntp | grep 8080

如果容器日志里服务已经起来了,但外部访问不到,通常就是下面三类问题之一:

  1. 服务只监听了容器内的 127.0.0.1
  2. 端口没有正确 -p 发布
  3. 宿主机网络策略把它拦住了

一些高频误区

容器里服务只监听 localhost

有些应用在容器里默认只监听 127.0.0.1。这时即使写了 -p 8080:8080,也可能从宿主机访问失败。

更稳妥的做法是让应用在容器内监听:

0.0.0.0:<container-port>

以为 docker run -p 会自动帮你做访问控制

-p 解决的是“映射到哪儿”,不是“谁被允许访问”。真正的访问边界还要看:

  • 宿主机防火墙
  • 云服务商安全组
  • 上游反向代理

宿主机端口已经被占了

如果 8080 已经被占用,容器启动时通常会直接报错。

这时先查:

ss -lntp | grep 8080
docker ps --format "table {{.Names}}\t{{.Ports}}"

然后要么换宿主机端口,要么停掉冲突服务。

我自己的默认选择

  • 临时调试或只给本机使用:127.0.0.1:host:container
  • 明确需要对外提供服务:0.0.0.0:host:container
  • 多网卡机器:显式绑定到目标 IP

关联阅读