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
如果容器日志里服务已经起来了,但外部访问不到,通常就是下面三类问题之一:
- 服务只监听了容器内的
127.0.0.1 - 端口没有正确
-p发布 - 宿主机网络策略把它拦住了
一些高频误区
容器里服务只监听 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