nginx映射docker容器内的域名,本质就是让nginx根据域名规则把请求转发给对应容器的IP和端口,配好server_name和proxy_pass即可。
很多人第一次接触docker部署时,都会卡在这一步:容器跑起来了,域名解析也指向了服务器,但浏览器输入域名就是打不开,原因很简单容器内部有自己的网络命名空间,nginx在宿主机上监听80端口,但容器里的服务并没有直接暴露出来,中间隔着一堵墙,打通这堵墙,就是今天要聊的重点。
nginx如何映射docker容器域名到宿主机端口
先弄明白请求的完整链路:用户输入域名 → DNS解析到服务器IP → 宿主机nginx接收请求 → 通过配置规则找到容器IP和端口 → 完成转发,其中最关键的就是两个配置指令:server_name 负责匹配域名,proxy_pass 负责指定转发目标。
在实际部署中,有两种主流场景,配置方式完全不一样:
- nginx在宿主机上,容器在docker网络里:需要拿到容器的内网IP或映射端口,直接转发到容器IP:端口。
- nginx本身也在容器里:需要通过docker内部网络来访问其他容器,这就涉及容器间的通信方式。
获取docker容器IP和端口信息
这条命令能看到容器的完整网络配置:
docker inspect 容器名 | grep -A 5 "NetworkSettings"
通常会得到类似 168.1.7 这样的内网IP,以及端口映射关系 8080/tcp -> 0.0.0.0:8080,这里有个细节要注意:容器内网IP不是固定的,容器重启后可能变化,所以更稳的做法是直接用docker的网络别名(alias)或容器名来访问。
宿主机nginx转发到容器
配置写在 /etc/nginx/conf.d/ 下,单独建一个域名配置文件:
server {
listen 80;
server_name web.example.com;
location / {
proxy_pass http://192.168.1.7:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
三个header是nginx反代的标配,proxy_set_header Host $host 尤其重要,不然容器里的应用拿到的是内网IP而不是你的域名,重定向和静态资源路径可能全部错乱。
docker部署nginx配置域名并实现容器间通信
这种场景更复杂一点,但也更常见,项目一般包含前端nginx容器、后端API容器、数据库容器,nginx要作为入口,把请求转发给其他容器,此时不能再填IP,因为容器的IP是动态的,而是要走 docker网络内部dns解析。
创建自定义docker网络
先把容器放到同一个网络中,这是容器间域名互通的前提:
docker network create webnet
启动容器时指定网络:
docker run -d --name backend --network webnet my-api-image docker run -d --name nginx-gateway --network webnet -p 80:80 nginx
两个容器在同一网络下,nginx容器里就能直接用容器名当域名来访问,配置改为:
server {
listen 80;
server_name web.example.com;
location /api/ {
proxy_pass http://backend:8080/;
}
location / {
proxy_pass http://frontend:3000;
}
}
容器名 backend 在docker网络内会被自动解析为对应容器的IP地址,不需要手动维护IP变化,重启容器也不影响。
用docker-compose编排场景
用compose启动时,服务名就是容器名,天然支持上述解析。docker-compose.yml 示例:
version: "3"
services:
backend:
image: my-api-image
networks:
- webnet
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
networks:
- webnet
networks:
webnet:
nginx配置文件已经挂载出来了,直接修改宿主机上的 nginx.conf 即可,改完reload,这是当前生产环境用得最多的部署方式。
下面是三种常见方案的对比,方便你根据自身情况选择:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 宿主机nginx直接转发容器IP | nginx装在宿主机,容器数量少 | 配置简单,直观 | 容器IP变化需要重新配置 |
| nginx容器加入同一docker网络 | 全容器化部署 | 用容器名通信,IP变化无感 | 需要额外维护网络配置 |
| 宿主机nginx转发到容器映射端口 | 不想动nginx容器,容器端口已映射到宿主机 | 不依赖docker网络 | 多一层NAT,性能略差 |
nginx容器内访问宿主机及域名解析常见问题
把nginx塞进容器后,遇到的第三个高频问题是:nginx容器内访问宿主机上的某些服务怎么办? 比如后端没容器化,直接跑在宿主机上,nginx容器里没法用 localhost 连到宿主机。
宿主机网关地址方案
docker容器默认通过 bridge 网络访问外网,宿主机在容器里的地址通常是 17.0.1,在nginx配置里直接写:
proxy_pass http://172.17.0.1:8080;
这种方式够用,但IP是docker默认网段,如果改了网段或用了 host 网络模式就不准了。
host.docker.internal方案
Docker Desktop(Windows/Mac)内置了 host.docker.internal 这个特殊域名,直接指向宿主机,Linux环境下需要加个参数才能用:
docker run -d --add-host host.docker.internal:host-gateway --name nginx-gateway nginx
然后在nginx配置里写 proxy_pass http://host.docker.internal:8080,这个方案更语义化,不易出错。
排查nginx映射docker容器域名失败的方向
遇到域名映射不上,多数情况不是nginx配置问题,而是连接链路上某个环节断了,按以下顺序检查:
- 容器端口有没有暴露:
docker ps看PORTS列,没映射的话外面根本访问不到容器。 - 容器之间能否互通:进入nginx容器执行
ping backend或curl http://backend:8080,不通就检查网络是否在同一个docker network下。 - 配置后有没有reload:改了配置文件必须
nginx -s reload,很多修改不生效都是因为这个。 - 服务防火墙规则:简米云、酷番云的服务器安全组里,80/443端口没放行会导致外部访问失败,但服务器本地curl正常。
行业共识认为,nginx容器化部署时应避免把域名写死在配置里,通过环境变量或配置文件挂载来管理不同环境的域名,能让运维省掉大量重复修改。
nginx映射docker容器多域名及HTTPS配置思路
单域名搞定后,多域名场景会复杂一些,但思路完全一致
每个域名一个server块,各自指向不同的容器。
server {
listen 80;
server_name a.example.com;
location / {
proxy_pass http://container-a:8080;
}
}
server {
listen 80;
server_name b.example.com;
location / {
proxy_pass http://container-b:9090;
}
}
HTTPS证书挂载方式
证书文件在宿主机上,nginx容器里需要挂载才能读取:
docker run -d -p 443:443 -v /etc/nginx/ssl:/etc/nginx/ssl:ro -v ./nginx.conf:/etc/nginx/conf.d/default.conf nginx
nginx配置里加上:
server {
listen 443 ssl;
server_name web.example.com;
ssl_certificate /etc/nginx/ssl/fullchain.pem;
ssl_certificate_key /etc/nginx/ssl/privatekey.pem;
location / {
proxy_pass http://backend:8080;
}
}
注意证书路径是容器内部的路径,不是宿主机路径。
批量管理多容器的配置实践
容器多了以后,逐条写server块容易乱,建议用include方式拆分配置:
http {
include /etc/nginx/conf.d/.conf;
}
每个域名单独建一个 .conf 文件,互不干扰,排查问题的时候只需要看对应域名的配置文件即可。
nginx映射docker容器域名常见问题解答
问:nginx容器里配了server_name为指定域名,访问IP却显示默认站点?
这是没匹配到server块导致回落到默认配置,先确认用 docker exec nginx-container nginx -T 查看实际加载配置,再检查访问请求的Host头是否确实与server_name一致,浏览器访问时如果域名没解析到服务器,直接填IP测试,此时Host是IP,当然不会命中域名规则。
问:nginx转发到容器名,但宿主机nginx解析不了backend这个名称?
宿主机nginx不在docker网络里,docker网络内的DNS解析对宿主机不生效,要么把宿主机nginx加入docker网络,要么改用容器映射到宿主机的IP和端口,二选一,没有第三种通用做法。
问:docker容器重启后nginx配置里的内网IP需要改吗?
如果nginx配置里写的是容器IP,重启后容器IP可能改变,需要重新修改配置并reload,换用docker网络中的容器名或服务名来访问,就能避免这类问题。
首发原创文章,作者:王坚,如若转载,请注明出处:https://idctop.com/article/626525.html





