反向代理:一个地址上的多个应用
如何按域名和路径让多个应用共用一个 VDS 公网地址、正确传递请求头,并且不破坏 WebSocket。
更新于 2026年8月23日
一台机器只有一个公网 IPv4 地址,但通常要运行多个应用。反向代理会接收 80 和 443 端口上的所有请求,并按域名或路径转发到内部服务。它还统一持有证书和共享日志。
布局
每个应用监听各自的本地端口,并且只监听 127.0.0.1:
- 前端站点 —
127.0.0.1:3000; - API —
127.0.0.1:8000; - 监控面板 —
127.0.0.1:9090。
只有 Nginx 对外暴露。要检查某个应用是否被直接暴露:
ss -tulpn | grep LISTEN
像 0.0.0.0:3000 这样的行表示该服务可以从互联网访问,绕过代理且没有加密。
按域名
server {
listen 80;
server_name app.example.ru;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name api.example.ru;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
如果没有 X-Forwarded-For,应用会把所有请求都看作来自 127.0.0.1,任何基于 IP 的限制都会失效。
按路径
location /api/ {
proxy_pass http://127.0.0.1:8000/;
}
这里 proxy_pass 末尾的斜杠很关键:带上它,/api 前缀会被去掉,应用收到的是 /users;不带它,应用收到的是 /api/users。代理上有一半的“莫名其妙的 404”正是由此而来。
WebSocket 与长响应
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
如果没有 Upgrade/Connection 这一对头部,连接会在握手后立刻断开;如果不延长超时时间,连接会在静默一分钟后断开。
常见错误
| 现象 | 原因 |
|---|---|
502 Bad Gateway | 应用没有运行,或监听的端口不同 |
504 Gateway Time-out | 应用的响应时间超过了 proxy_read_timeout |
| 无限重定向 | 应用不知道 HTTPS — 请传递 X-Forwarded-Proto |
| 文件上传失败 | client_max_body_size 太小;默认值为 1 MB |
| 应用日志中都是同一个 IP | 没有传递 X-Forwarded-For |
代理上的一个证书即可覆盖其后的所有应用。通过
127.0.0.1的内部连接不需要加密 — 它们永远不会离开这台机器。