从欢迎页到反向代理:一次 Nginx 容器配置排错实录
一个看似简单的 Nginx 反向代理问题,背后是 server 块优先级、配置文件加载顺序的深度排查。
背景
前段时间,我把自己手工搭建的高可用集群(Keepalived+Nginx+Tomcat+MySQL)全部容器化,并用 Docker Compose 管理。在 Backup 主机(192.168.211.135)上,Nginx 容器正常运行,但在容器内 curl 可以正常访问 Tomcat 页面,而通过宿主机 IP 或外部浏览器访问时,却始终返回 Nginx 默认欢迎页。这是一个典型的“内外不一致”问题,我花了不少时间才找到根因。本文将完整记录排查与解决过程。
一、现象
在 Backup 主机上,执行:
docker exec -it nginx curl http://127.0.0.1
返回 Tomcat 页面(正确)。 但执行:
curl http://192.168.211.135
返回 Nginx 默认欢迎页(错误)。 Windows 浏览器访问同样结果。
二、排查思路
2.1 确认 80 端口监听方
ss -tlnp | grep :80
输出显示 nginx 进程在监听 80 端口,且进程路径为容器内的 nginx(不是宿主机 nginx),说明容器已正确接管端口。
2.2 检查容器内配置文件
docker exec -it nginx ls /etc/nginx/conf.d/
发现两个文件:default.conf 和 tomcat.conf。 查看 tomcat.conf 内容:
upstream web {
server 192.168.211.128:8081;
server 192.168.211.133:8081;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://web;
}
}
配置看起来正确。
2.3 检查主配置文件
docker exec -it nginx cat /etc/nginx/nginx.conf
确认 http 块内包含 include /etc/nginx/conf.d/*.conf;,说明配置文件都会被加载。
2.4 查看所有监听 80 的 server 块
docker exec -it nginx sh -c "nginx -T 2>/dev/null | grep -A 10 'listen\s*80'"
输出显示两个 server 块:
-
第一个来自 default.conf,server_name localhost,根目录 /usr/share/nginx/html。
-
第二个来自 tomcat.conf,server_name _,反向代理。
关键点:当请求的 Host 头(例如 192.168.211.135)与任何 server_name 都不匹配时,Nginx 会选择第一个定义的 server 块来处理。由于 default.conf 先被加载,它成为了默认 server,因此返回欢迎页。
2.5 验证优先级
在容器内模拟外部请求:
docker exec -it nginx curl -v --header "Host: 192.168.211.135" http://127.0.0.1
返回 404(因为 default.conf 的根目录没有对应文件),证实了请求被第一个 server 块处理。
三、解决方案
要让 tomcat.conf 成为唯一的 80 端口 server 块,必须消除 default.conf 的干扰。 最直接的方法:覆盖 default.conf 为空文件。
3.1 创建空文件
touch /opt/nginx-backup/default.conf
3.2 修改 docker-compose.yml,挂载空文件到正确位置
services: nginx: image: my-nginx:1.1 container_name: nginx restart: always network_mode: host volumes: - /etc/localtime:/etc/localtime:ro - /opt/nginx-backup/tomcat.conf:/etc/nginx/conf.d/tomcat.conf:ro - /opt/nginx-backup/nginx.conf:/etc/nginx/nginx.conf:ro - /opt/nginx-backup/default.conf:/etc/nginx/conf.d/default.conf:ro # 覆盖
注意:必须挂载到 /etc/nginx/conf.d/default.conf,而非 /etc/nginx/default.conf,因为 Nginx 只加载 conf.d 目录下的 .conf 文件。
3.3 重新创建容器
cd /opt/nginx-backup docker-compose down docker-compose up -d
3.4 验证
curl http://192.168.211.135
此时返回 Tomcat 页面,问题解决。
四、原理总结
· Nginx 加载顺序:include 指令按文件名字母顺序加载配置文件,因此 default.conf 先于 tomcat.conf。 · 默认 server 块:当请求的 Host 头不匹配任何 server_name 时,Nginx 会使用第一个监听的 server 块作为默认。 · 解决方案:删除或覆盖默认的 server 块,让自定义配置成为第一个(或唯一)的 server 块。
五、踩坑与反思
-
配置文件位置:一开始我误将空文件挂载到 /etc/nginx/default.conf,导致无效。必须确认正确的加载路径。
-
检查所有监听:使用 nginx -T 查看完整配置,避免遗漏。
-
区分内部与外部访问:容器内 curl 127.0.0.1 成功不代表外部请求能正确路由,因为 Host 头不同。
-
优先采用挂载而非 docker cp:挂载方式便于调试和持久化,避免容器重启后配置丢失。
六、最终成果
现在,Backup 主机上的 Nginx 容器已能正常反向代理到 Tomcat 集群,访问 Backup IP 和 VIP 均返回正确页面。整个高可用容器化项目(MySQL、Tomcat、Nginx)已通过 Docker Compose 实现一键部署,后续可扩展监控、日志、CI/CD 等功能。
如果你也遇到类似问题,希望这篇文章能帮你少走弯路。欢迎留言交流!
更多推荐
所有评论(0)