Docker + Nginx + Node.js:从端口映射到反向代理的完整请求链路
Docker + Nginx + Node.js:从端口映射到反向代理的完整请求链路
很多初学者能照着执行 docker run,却分不清 -p 80:80、listen 80 和 proxy_pass ...:3000 各自负责什么。本文围绕 Windows Docker Desktop 下的一个最小 Nginx + Node.js 示例,拆清镜像、容器、文件挂载、端口映射与反向代理的关系,并给出排错清单。文中代码根据学习材料整理,运行未验证。
一、先看最终请求链路
浏览器访问 localhost:80
↓
Windows 宿主机 80 端口
↓ Docker 端口映射 -p 80:80
Nginx 容器 80 端口
↓ proxy_pass
host.docker.internal:3000
↓
Windows 上的 Node.js 服务
理解这条链路后,命令与配置就不再是孤立知识点。
二、镜像与容器是什么关系
Docker 可以把应用及运行所需内容组织成镜像,再基于镜像启动容器:
镜像 Image --docker run--> 容器 Container
- 镜像是只读模板,类似带运行环境的应用模板。
- 容器是镜像运行后的实例。
- Docker Hub 是默认的公共镜像仓库之一。
下载 Nginx 镜像:
docker pull nginx
这里应使用 docker pull,不是 Git 的 git pull。下载镜像并不会自动提供服务,还需要 docker run 创建并启动容器。
三、拆解 docker run 命令
Windows PowerShell 中可以使用:
docker run --name my-nginx-demo -p 80:80 -v "C:\path\nginx.conf:/etc/nginx/nginx.conf" -d nginx
| 参数 | 作用 | 初学者常见误解 |
|---|---|---|
--name my-nginx-demo | 指定容器名称 | 同名容器不能重复创建 |
-p 80:80 | 宿主机 80 映射到容器 80 | 左边是宿主机,右边是容器 |
-v | 把本机配置挂载进容器 | Windows 路径建议整体加引号 |
-d | 后台运行 | 返回容器 ID 不代表服务持续正常 |
nginx | 使用 Nginx 镜像 | 镜像与容器不是同一个概念 |
端口映射只解决:浏览器如何把请求送到容器里的 Nginx。它还没有决定 Nginx 要把请求交给哪个后端。
四、Nginx 配置如何转发到 Node.js
最小配置如下:
events {}
http {
server {
listen 80;
location / {
proxy_pass http://host.docker.internal:3000;
proxy_set_header Host $host;
}
}
}
逐项理解:
listen 80:Nginx 在容器内部监听 80 端口。location /:匹配从根路径开始的请求。proxy_pass:把请求转发给指定后端。host.docker.internal:Docker Desktop 容器访问 Windows 宿主机时使用的特殊域名。proxy_set_header Host $host:把原请求的 Host 请求头继续传给后端。
因此,listen 80 是 Nginx 的入口,:3000 是后端 Node.js 的入口,两者不是同一个端口。
五、端口映射不等于反向代理
这是最容易混淆的地方。
端口映射
Windows:80 → Nginx 容器:80
由 Docker 完成,解决宿主机与容器之间的网络入口问题。
反向代理
Nginx:80 → Node.js:3000
由 Nginx 根据 proxy_pass 完成,解决统一入口向真实后端转发的问题。
浏览器只访问 Nginx,不需要知道 Node.js 的地址和端口,所以 Nginx 在这里是反向代理。
六、Node.js 示例中的模块错误
Node.js 入口使用 .mjs 后缀,意味着文件按 ESM 处理,应使用:
import http from 'node:http';
不能再同时写:
const http = require('http');
否则既会遇到 ESM 中没有 require 的问题,也会重复声明 http。即使 package.json 中设置了 "type": "commonjs",.mjs 仍按 ESM 解释。
后端计划监听 3000 端口:
server.listen(3000, 'localhost', () => {
console.log('server is running on port 3000');
});
容器能否通过宿主机网络访问仅监听 localhost 的服务需要实际验证。开发场景中通常可考虑监听 0.0.0.0,但仍应结合安全边界配置。
七、错误—原因—处理表
| 现象 | 常见原因 | 排查方式 |
|---|---|---|
docker run 提示名称冲突 | 已存在同名容器 | docker ps -a,启动、删除或改名 |
docker ps 看不到容器 | 容器已经退出 | 使用 docker ps -a |
| Nginx 容器立即退出 | 配置语法或指令层级错误 | docker logs my-nginx-demo |
proxy_pass directive is not allowed here | proxy_pass 不在允许的上下文 | 放到 location 等合法配置块中 |
| 浏览器返回 502 | Node.js 未启动、端口错误或网络不可达 | 检查 3000 端口和监听地址 |
require is not defined | .mjs 使用了 CommonJS 语法 | 改用 import |
八、最终自检清单
- Docker Desktop 已启动。
- 已使用
docker pull nginx获取镜像。 - 本机 80 端口未被其他程序占用。
-
-p左边是宿主机端口,右边是容器端口。 - Windows 挂载路径已加引号。
-
proxy_pass位于location中。 - Node.js 确实监听 3000 端口。
-
docker ps中 Nginx 状态为Up。 - 失败时已查看
docker logs。
九、面试回答模板
Docker 镜像是应用及运行环境的只读模板,容器是镜像的运行实例。
docker run -p 80:80将宿主机 80 端口映射到 Nginx 容器的 80 端口;Nginx 再通过proxy_pass把请求转发到 Node.js 的 3000 端口。端口映射解决宿主机到容器的入口问题,反向代理解决统一入口到真实后端的请求转发问题。
十、结语
学习这组技术时,不要只背命令。始终沿着“浏览器 → 宿主机端口 → 容器端口 → Nginx → Node.js”检查,请求在哪一段断开,问题通常就在哪一层。下一步可以补充 Dockerfile、Docker Compose、容器网络和数据卷,让多个服务从手工命令走向可复现编排。
标签: Docker、Nginx、Node.js、反向代理、容器化
更多推荐

所有评论(0)