nginx反代502报错解决


起因是cgt用的自签名证书导致api访问会因为证书不安全导致资源加载失败,申请了企业的域名,由于企业的域名只能在机房电脑上,所以需要加一层lb,为了防止部署后影响制作,先用自己的域名

生产力工具上场,一下为gpt-5-chat的沟通

提出需求

server {
    listen 60288 ssl;
    listen [::]:60288 ssl;
    server_name cgt.tdxinglian.com;

    ssl_certificate     /media/nas/docker_images/acme/data/certd/ssl/cert.crt;
    ssl_certificate_key /media/nas/docker_images/acme/data/certd/ssl/cert.key;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_ciphers         HIGH:!aNULL:!MD5;

    location / {
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        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_connect_timeout 60s;
        proxy_send_timeout 120s;
        proxy_read_timeout 120s;

        proxy_pass http://180.184.58.112:8181;
    }
}
这是docker中的nginx配置, 其中的80端口映射到的宿主机的8181端口,8686映射到宿主机的8686端口, 现在我需要在另一台电脑上做一个nginx的转发,cgt.tdxinglian.com会解析到这台新的电脑的ip, 宿主机的ip是180.184.58.112, 60288, 60289 分别对应宿主机的8181, 8686,60288跟60289都是https端口 8181是纯http端口, 8686是wss端口 ssl_certificate /media/nas/docker_images/acme/data/certd/ssl/cert.crt; ssl_certificate_key /media/nas/docker_images/acme/data/certd/ssl/cert.key; 证书路径是这个,写一个完整的nginx.conf文件给我	

给出答案

ssl_protocols TLSv1.2 TLSv1.3; 禁用低强度加密套件, 这句与server语句同一层级

# 启用websocket (wss端口)
proxy_http_version 1.1;  # wss端口版本必须是1.1
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

访问测试 直接ip访问正常,域名访问返回502,贴上报错信息

upstream prematurely closed connection while reading response header from upstream

日常抽搐

还是会出现回复死循环,这种时候最好清空上下文,整理有用信息,重新开启回话
中间gpt多次纠结反代机器与cgt之间的网络是否能连接,清除上下文,将 curl -v -follow访问ip与域名的log放在一次会话中告诉gpt

为什么反代会 502 而 curl 正常

原因可能是:

  • 302 重定向 + Host 头
    上游返回的是相对路径 index.php?...,Nginx 会转发这个响应给客户端。
    如果客户端是TTPS(60288端口)而上游是 HTTP,某些情况下浏览器会尝试直接访问上游返回的绝对/相对地址,却走错协议或端口,从而显示错误。
    Nginx 在默认配置下不会出错,但如果 upstream 关闭连接太快(302时没有返回完整的Body等),也可能导致 upstream prematurely closed connection → 502。
  • 解决方案方向
    既然 curl 发正常结果,那让 Nginx 按 curl的行为来适配上游返回即可。
    proxy_http_version 1.0; # 避免 chunked 响应问题
    proxy_set_header Connection close; # 立即关闭,防止长连接问题

另外如果上游返回的 Location 是相对路径,浏览器没问题。但如果是绝对路径并带协议,可能需要:
proxy_redirect off; 或者 proxy_redirect http://$proxy_host https://$host:$server_port;
这样反代会把上游的重定向改成前端的 HTTPS 地址,不会跳错。

根据回答修改,并再次使用curl -vk进行测试

可能的原因

上游返回信息

HTTP/1.1 302 Found 
Location: index.php?controller=v_login&method=show_page 
Set-Cookie: ws_port=8686

这是一个相对路径的重定向。

Nginx 在反代这种响应时:

  • 如果使用 HTTP/1.1 且启用了 Connection: keep-alive,上游可能会在发送响应头后立刻断开连接,Nginx 就认为响应未完成,从而直接 502。
  • 如果上游是 PHP-FPM/nginx 组合,某些 chunked/no-body 响应在反代时会触发这种错误。
  • proxy_set_header Connection "" 或 keep-alive 对这种老式短连接响应不友好,需要改为关闭连接。
  • 我怀疑上游是 PHP 或某个应用网关,它对 Host 非常敏感,你现在反代发的是:
    Host: cgt.tdxinglian.com:60288
    而直接 curl http://180.184.58.112:8181 发的是:
    Host: 180.184.58.112:8181
    这种差异在某些应用会导致直接退出连接。

解决方法

我们在反代时可以强制:

  1. 使用 HTTP/1.0 转发(避免 chunked 传输和 keep-alive 对这种场景的影响)。
  2. 强制关闭连接。
  3. 禁用自动修改重定向头(防止 proxy_redirect 把相对路径改出问题)。
  4. 反代改成 proxy_set_header Host 180.184.58.112;

修改后的 nginx.conf 示例(针对 60288 端口的 HTTP 反代):

为什么这样能解决

  • HTTP/1.0 + Connection close
    每个请求/响应独立,不依赖持久连接,避免“上游提前关闭连接”导致 Nginx 报 502。
  • proxy_redirect off
    避免 Nginx 强制把 HTTP 重定向改成 HTTPS,保持上游返回的相对路径。
  • 3、4步的修改可以模拟直连时的请求头,使反代更接近你直接 curl 上游的行为,而你直接 curl 是正常的。

评论
  目录