如何把不同子域名转发到同一服务器的不同端口
用 Apache 的 VirtualHost + ProxyPass(或 Nginx 的 server 块 + proxy_pass)按域名把请求反向代理到本机不同端口,用户访问 app.example.com 实际由 8080 端口服务。附完整配置与 WebSocket 处理。
一句话回答:用反向代理按域名分发:Apache 里为每个子域名建一个 VirtualHost,用 ProxyPass / http://localhost:端口/ 转发;Nginx 里同理用 server 块 + proxy_pass。这样 app.example.com、api.example.com 都走 80/443 进入,实际分别由本机 8080、3000 端口的服务处理,用户完全看不到端口号。
Apache 配置
先启用代理模块:
sudo a2enmod proxy proxy_http
sudo systemctl restart apache2
为每个子域名建 VirtualHost:
<VirtualHost *:80>
ServerName app.example.com
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
<VirtualHost *:80>
ServerName api.example.com
ProxyPass / http://127.0.0.1:3000/
ProxyPassReverse / http://127.0.0.1:3000/
</VirtualHost>
ProxyPassReverse 的作用是改写后端响应里的重定向地址,建议配套配置;它不改写 HTML 内容或所有 Cookie 属性,应用的外部 URL 配置也要正确。
Nginx 等价配置
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1: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;
}
}
这些转发头让后端获得入口看到的 Host/IP 信息;应用只应信任来自已知代理的头,不能无条件信任客户端自带的 X-Forwarded-For。容器分离部署时 127.0.0.1 未必指向后端,应换为可达服务地址。
WebSocket 服务要额外处理
如果被代理的服务用 WebSocket(如热更新、实时推送),需要升级头支持:
# Nginx:location 块内加
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
配套事项
- DNS:各子域名用 A/AAAA 或合适的 CNAME 解析到代理入口;DNS 不负责端口路由
- HTTPS:生产环境给每个子域名配证书(或一张泛域名证书),用 Certbot 可自动签发并改写配置
- 后端服务绑定 127.0.0.1:8080/3000 端口只监听本机,外部无法绕过代理直连,更安全
逐一请求各子域名,核对响应来自预期后端;同时查看代理访问日志中的域名与上游地址,防止多个域名误入默认站点。
常见问题(FAQ)
Q:为什么不用 子域名:端口 直接访问,非要反向代理?
A:三个原因:URL 里的端口号对普通用户不友好;很多公司/校园网络封非标准端口,8080 直接访问会被拦;HTTPS 证书和统一入口难以管理。反向代理用标准 80/443 一口进,内部按域名分流,是标准做法。
Q:配置后访问子域名出现 503?
A:503 可能来自代理或后端,不能只凭状态码断定端口拒绝连接;结合错误日志:确认后端服务在跑(ss -tlnp | grep 8080)、后端没崩;Apache 场景还可检查 SELinux 拒绝日志,确认策略原因后由管理员按最小权限调整,勿直接放宽全局策略。
Q:不同子域名必须指向不同端口吗?
A:不一定。如果多个子域名由同一个应用处理(如多租户),可以让多个 server_name 共用同一个 proxy_pass 目标,应用内按 Host 头区分租户。
核查依据
本文依据官方文档核对,示例未在实际业务环境运行;上线前请按部署版本、权限与数据范围验证。