一、问题描述
在 Docker 部署前端 SPA(Vue / React)时,常遇到以下问题:
- 访问
http://host:9990/oimcs - 被 Nginx 301 重定向后
- 浏览器地址栏变成
http://host/oimcs/ - 端口丢失
导致:
- 页面无法访问
- API 请求失败
- 前端路由异常
二、根本原因(核心认知)
1️⃣ Nginx 无法感知 Docker 映射端口
| 层级 | 知道的端口 |
|---|---|
| Docker Host | ✅ 9990 |
| Docker NAT | ✅ |
| 浏览器 | ✅ |
| Nginx(容器内) | ❌ 只知 80 |
👉 Nginx 永远不知道外部端口是多少
2️⃣ 只有 3xx 重定向才会出问题
| 行为 | 端口来源 | 是否安全 |
|---|---|---|
| 前端路由跳转 | 浏览器 | ✅ |
| axios / fetch | 浏览器 | ✅ |
<a> 链接 | 浏览器 | ✅ |
| 301 / rewrite | Nginx | ❌ |
✅ 前端跳转永远不会丢端口
❌ Nginx 重定向才会
三、错误做法(为什么以前会失败)
❌ 写死端口
return 301 http://host:80/oimcs/;
- Docker 端口一变就炸
- 多环境不可维护
❌ 依赖 Nginx 自动补端口
port_in_redirect on;
- 自动补成 80
- Docker 映射端口直接失效
四、正确解决方案(本仓库采用)
✅ “端口统一 + 相对路径重定向 + 环境变量注入”
五、本仓库的实现机制(逐层说明)
1️⃣ Nginx 配置:永远不写端口
nginx.conf.template
server {
listen ${NGINX_PORT};
server_name _;
location = /oimcs {
return 301 /oimcs/;
}
}
✅ 关键点
| 项 | 说明 |
|---|---|
listen ${NGINX_PORT} | 由环境变量注入 |
return 301 /oimcs/ | 相对路径 |
不使用 port_in_redirect | 避免干扰 |
👉 浏览器自己补端口,永远不会错
2️⃣ Dockerfile:运行时生成配置
Dockerfile
ENV NGINX_PORT=80
CMD ["sh", "-c", "\
envsubst '${NGINX_PORT}' \
< /etc/nginx/nginx.conf.template \
> /etc/nginx/nginx.conf && \
nginx -g 'daemon off;' \
"]
✅ 设计意图
| 阶段 | 行为 |
|---|---|
| 构建 | 不含端口 |
| 启动 | 注入端口 |
| 运行 | 配置生效 |
👉 解决 Nginx 无法感知 Docker 端口的问题
3️⃣ Docker Compose:端口只在一处定义
.env
NGINX_PORT=80
docker-compose.yml
ports:
- "${NGINX_PORT}:${NGINX_PORT}"
environment:
- NGINX_PORT=${NGINX_PORT}
✅ 保证三层一致
| 层级 | 端口 |
|---|---|
| 宿主机 | 80 |
| Docker 映射 | 80 |
| Nginx 监听 | 80 |
👉 端口完全一致,重定向无风险
六、为什么这套方案是“终极解”
✅ 不依赖 Nginx 猜测端口
✅ 不写死配置
✅ 支持多环境
✅ 支持 Watchtower
✅ 支持 CI/CD
七、常见疑问解答
❓ 新版本 Nginx 会解决这个问题吗?
❌ 不会
Nginx 不感知 Docker,也不可能自动识别映射端口。
❓ 前端路由会不会丢端口?
✅ 不会
前端跳转全部由浏览器基于当前 URL 拼接。
❓ 后端 API 会不会受影响?
✅ 不会
proxy_pass http://gateway/ 不涉及端口重定向。
八、总结一句话
Docker + Nginx 端口丢失问题,不是 Nginx 的 Bug,而是架构边界问题。
本方案通过“端口统一 + 相对路径重定向 + 环境变量注入”,一次性根治。
✅ 本仓库当前配置已封板,可直接用于生产环境。


评论区