Nginx跨服务器子域名配置异常:vscode.domain.tld请求被跳转到hub.domain.tld问题排查
嘿,我来帮你捋清楚这个问题——你遇到的其实是跨服务器反向代理里很常见的「请求路由错位」问题,咱们一步步拆解原因和解决方案:
问题根源分析
首先得明确一个关键事实:你的公网DNS和端口转发规则都是指向第一台服务器(192.168.1.216)的。这意味着,不管用户访问的是hub.domain.tld还是vscode.domain.tld,所有发往80/443端口的请求都会先落到第一台服务器的Nginx上,根本没机会到达第二台服务器的Nginx。
而第一台服务器的Nginx里应该有默认的跳转规则(比如默认server块会把未匹配的请求跳转到hub.domain.tld),所以当你访问vscode.domain.tld时,第一台服务器的Nginx找不到对应的配置,就触发了默认跳转——这就是为什么把vscode的配置移到第一台服务器就正常,因为此时它能正确识别这个子域名的请求了。
解决方案(结合你容器化拆分的需求)
根据你想拆分配置、容器化code-server/questdb/grafana的目标,有两个靠谱的方案可选:
方案1:让第二台服务器直接接收公网请求(独立路由)
如果想让第二台服务器单独负责vscode.domain.tld的请求,需要调整网络层面的配置:
- 要么给第二台服务器分配独立的公网IP,然后把
vscode.domain.tld的DNS记录指向这个新IP; - 要么在你的路由器/防火墙里,针对
vscode.domain.tld的80/443请求单独设置端口转发,把流量导到第二台服务器的内网IP(192.168.1.234); - 确保第二台服务器的Nginx配置(就是你现在贴的那段)没有问题,且内网防火墙允许公网转发过来的流量。
方案2:以第一台服务器为统一入口,转发请求到第二台(更适合容器化集群)
这个方案更符合你拆分配置、容器化服务的长期规划——把第一台服务器作为公网反向代理入口,统一处理所有子域名的SSL和路由,第二台服务器专注于容器化服务的内部代理:
步骤1:在第一台服务器的Nginx中添加vscode.domain.tld的路由配置
把原来在第二台服务器的vscode配置迁移到第一台,调整proxy_pass指向第二台服务器的code-server(或者第二台的Nginx):
# top-level http config for websocket headers(和你原来的一致,保留在第一台的主配置里) map $http_upgrade $connection_upgrade { default upgrade; '' close; } # HTTP服务器:跳转到HTTPS server { listen 80; server_name vscode.domain.tld; return 302 https://$host$request_uri; } # HTTPS服务器:处理vscode请求,转发到第二台服务器 server { listen 443 ssl; server_name vscode.domain.tld; ssl_certificate /etc/letsencrypt/live/vscode.domain.tld/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/vscode.domain.tld/privkey.pem; # 以下SSL配置和你原来的完全一致,直接复制即可 ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; ssl_dhparam /etc/ssl/certs/dhparam.pem; ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA'; ssl_session_timeout 1d; ssl_session_cache shared:SSL:50m; ssl_stapling on; ssl_stapling_verify on; add_header Strict-Transport-Security max-age=15768000; # 转发请求到第二台服务器的code-server location / { proxy_pass http://192.168.1.234:8080; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # websocket相关配置 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Scheme $scheme; proxy_buffering off; } # Let's Encrypt验证路径 location ~ /.well-known { allow all; } }
步骤2:第二台服务器的Nginx专注于容器化服务的内部代理
把第二台的Nginx配置简化,只负责转发容器内的code-server、questdb、grafana请求(可以用Docker Compose把这些服务和Nginx容器放在同一个网络里):
server { listen 80; server_name localhost; # 转发code-server请求(如果直接让第一台连code-server,这部分可以省略) location / { proxy_pass http://code-server:8080; # 对应websocket配置和你原来的一致 proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # 转发questdb请求 location /questdb/ { proxy_pass http://questdb:9000/; proxy_set_header Host $host; } # 转发grafana请求 location /grafana/ { proxy_pass http://grafana:3000/; proxy_set_header Host $host; } }
步骤3:Docker Compose配置参考
在第二台服务器上编写docker-compose.yml,把所有服务放在同一个网络,让Nginx能直接访问:
version: '3.8' services: nginx: image: nginx:alpine ports: - "8080:80" # 或者映射到你需要的端口 volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf networks: - app-network code-server: image: codercom/code-server:latest volumes: - ./code-server-config:/home/coder/.config/code-server networks: - app-network questdb: image: questdb/questdb:latest volumes: - ./questdb-data:/root/.questdb networks: - app-network grafana: image: grafana/grafana:latest volumes: - ./grafana-data:/var/lib/grafana networks: - app-network networks: app-network: driver: bridge
额外注意事项
- 确保第一台和第二台服务器之间的内网网络连通,没有防火墙阻挡对应端口(比如8080、80等);
- Let's Encrypt证书建议统一在第一台服务器申请,这样所有子域名的SSL都由入口代理处理,更易维护;
- 如果选择方案2,第一台服务器的Nginx可以继续保留
hub.domain.tld的配置,实现多子域名的统一路由。
备注:内容来源于stack exchange,提问作者Bouarfa Mahi

