新闻详情

新闻详情

首页 / 资讯中心 / 详情

Linux Nginx WebSocket 代理提示 502 错误怎么检查后端状态

发布时间:2026/10/2 4:11:12来源:尧图网络
Linux Nginx WebSocket 代理提示 502 错误怎么检查后端状态
前言浏览器控制台里看到WebSocket connection to wss://xxx/ws failed: Error during WebSocket handshake: Unexpected response code: 502或者前端库报一个笼统的 502是最让人抓瞎的一类故障。因为这条连接的两端——Nginx 和后端应用——都不在你的浏览器里502 只说了一句话Nginx 没法从上游拿到一个合法的响应。很多人的第一反应是去重启后端进程重启完确实好了过一会儿又 502。这说明你修的是症状不是病因。502 在 WebSocket 场景下有非常集中的几种成因后端根本没在监听、后端在握手阶段主动关连接、Nginx 少传了三个关键头部、SELinux 拦掉了 Nginx 出站连接。本文按先分流、再逐项排除的顺序给出一套可以直接复制执行的排查命令并把proxy_http_version/Upgrade/Connection这三个必须项讲清楚。需要先纠正一个常见误解502 只在握手阶段产生。握手成功后连接已经升级成 WebSocket 帧流此时上游断开Nginx 不会再给你一个 502浏览器拿到的是onclose且code为 1006。所以连上 60 秒后掉线和一开始就 502是两类完全不同的故障排查路径也不一样。以下命令基于 RHEL 9 / nginx 1.24AppStream 模块流与 Debian 12 / nginx 1.22路径差异已在文中标注。请先用nginx -v确认你自己的版本。一、先判断 502 出现在哪个时刻把浏览器 Network 面板切到 WS 标签或者直接用curl手工发一次握手观察失败时间点。curl -i -N \ -H Connection: Upgrade \ -H Upgrade: websocket \ -H Sec-WebSocket-Version: 13 \ -H Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ \ http://127.0.0.1/ws三种结果对应三条不同的路现象含义优先排查方向立刻返回 502响应体是 Nginx 的默认错误页Nginx 连不上上游或上游秒退error.log的connect() failed/prematurely closed挂起约 60 秒后返回 504不是 502上游连上了但不回数据proxy_read_timeout或后端逻辑卡死返回 101 Switching Protocols 后又断开握手其实是好的心跳/超时不是本文的 502 问题Sec-WebSocket-Key按 RFC 6455 必须是 16 字节的 base64上面用的dGhlIHNhbXBsZSBub25jZQ是协议标准文档里的示例值直接可用。二、Nginx 侧error.log 会直接告诉你原因WebSocket 的 502 几乎不需要猜Nginx 的错误日志会给出上游 IP、端口和 errno。用nginx -T先导出最终生效的完整配置确认你改的文件真的被 include 了。# 导出最终配置并检查 webSocket 相关片段 nginx -T 2/dev/null | grep -n -A12 location /ws # 实时观察错误日志Debian 12: /var/log/nginx/error.log tail -f /var/log/nginx/error.log对照下表定位error.log 片段原因处理connect() failed (111: Connection refused)后端没监听或端口写错ss -lntp确认监听地址与端口connect() to ... failed (13: Permission denied)SELinux 拦截 Nginx 出站连接见第四节upstream prematurely closed connection while reading response header后端进程崩了/主动 close查后端日志与dmesgupstream sent invalid header后端返回的字节不是合法 HTTP 响应直连后端curl -i看原始输出no live upstreams while connecting to upstream上游被健康检查全部标记为 down检查max_fails/fail_timeout2.1 三个必须写对的头部这是 WebSocket 反代最经典的坑。Nginx 默认以HTTP/1.0与上游通信并且默认会把Connection头改写成close。这两件事任何一个没改后端就拿不到升级请求ws库通常直接关连接Nginx 于是回你 502。# 作用域http 块map 必须写在 server 之前 map $http_upgrade $connection_upgrade { default upgrade; close; } server { listen 80; server_name ws.example.com; location /ws { proxy_pass http://127.0.0.1:8080; proxy_http_version 1.1; # 必须默认是 1.0 proxy_set_header Upgrade $http_upgrade; # 必须 proxy_set_header Connection $connection_upgrade; # 必须别写死 upgrade 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_read_timeout 3600s; # 空闲连接保活默认 60s proxy_send_timeout 3600s; proxy_buffering off; # 长连接场景建议关掉缓冲 } }$connection_upgrade这个写法来自 Nginx 官方 WebSocket 反代文档好处是普通 HTTP 请求走同一个 location 时Connection会自动变成close而不是被硬编码成upgrade。改完务必先测语法再重载nginx -t nginx -s reload三、后端侧绕开 Nginx 直接打如果error.log显示Connection refused说明问题已经不在 Nginx 了。按这个顺序查# 1. 看端口是否在监听注意是 127.0.0.1 还是 0.0.0.0 ss -lntp | grep -E 8080|LISTEN # 2. 直接对后端发一次握手完全不经过 Nginx curl -i -N \ -H Connection: Upgrade -H Upgrade: websocket \ -H Sec-WebSocket-Version: 13 \ -H Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ \ http://127.0.0.1:8080/ws # 3. 后端是 systemd 服务时看它为什么退出 systemctl status myapp --no-pager journalctl -u myapp -n 100 --no-pager # 4. 后端被 OOM 杀掉的情况容器里尤其常见 dmesg -T | grep -i -E oom|killed process如果第 2 步直接返回101而经过 Nginx 返回 502那 100% 是第二节的头部或proxy_pass写法问题不要再去动后端。还要注意proxy_pass的 URI 部分proxy_pass http://127.0.0.1:8080;会把原始 URI 原样透传proxy_pass http://127.0.0.1:8080/;会把location匹配到的前缀替换掉。后者很容易让/ws变成/打到后端后端自然 404 或直接断连。四、SELinux最容易被忽略的 502 来源在 RHEL / CentOS / Rocky / AlmaLinux 上SELinux 处于enforcing时Nginx 默认不允许主动发起网络连接。后端起在 8080、9000 这类非标准端口上时你会在error.log里看到(13: Permission denied)而不是Connection refused——但浏览器看到的同样是 502。# 确认 SELinux 状态 getenforce # 查看布尔值开关 getsebool -a | grep httpd_can_network_connect # 放行 Nginx 出站连接-P 持久化到重启后 setsebool -P httpd_can_network_connect 1 # 如果后端跑在自定义端口上还需要放行该端口 semanage port -l | grep -E ^http_port_t semanage port -a -t http_port_t -p tcp 8080semanage由policycoreutils-python-utils提供dnf install -y policycoreutils-python-utils另外SELinux 还会因为拒绝动作在/var/log/audit/audit.log留下记录用ausearch能直接看到被拒的具体操作ausearch -m avc -ts recent | grep nginx常见坑点❌ 只写proxy_set_header Connection upgrade;忘了proxy_http_version 1.1;✅ 两者必须成对出现。HTTP/1.0 下Upgrade语义不成立后端会当成普通请求处理。❌ 把Connection头硬编码成upgrade导致同一个 location 下的普通 HTTP 请求也被标成升级请求。 ✅ 用map $http_upgrade $connection_upgrade { default upgrade; close; }让非升级请求走close。❌ 以为把proxy_read_timeout从 60s 调到 3600s 就能解决60 秒后 502。 ✅ 握手成功后 Nginx 不会再回 50260 秒断线是连接被关浏览器报 1006。真正的解法是应用层心跳ping/pong加上合理超时。❌ 反复重启后端不去看error.log。 ✅ 先tail -f /var/log/nginx/error.log再复现一次errno 会直接指出是连接、权限还是协议问题。❌ 在 RHEL 系上只改了防火墙firewall-cmd就以为通了。 ✅ SELinux 的拦截发生在内核层防火墙放行不代表 Nginx 能连出去getenforce和ausearch都要看。❌ 用proxy_pass http://127.0.0.1:8080/;带尾斜杠却期望/ws原样透传。 ✅ 带 URI 的proxy_pass会做前缀替换要么去掉尾斜杠要么显式对齐 location 与后端路由。❌ 在location里加rewrite ... break;之后再proxy_pass以为 URI 不变。 ✅break会改变当前location内后续处理所用的 URIproxy_pass不带 URI 时透传的是改写后的值排查时用nginx -T看最终结果。❌ 调试时用curl http://127.0.0.1/ws不带任何头部得到一个 400 就以为后端坏了。 ✅ WebSocket 握手必须带Upgrade、Connection、Sec-WebSocket-Key、Sec-WebSocket-Version: 13四个头缺一个就不构成合法握手。总结排查层次命令 / 配置关键判据Nginx 日志tail -f /var/log/nginx/error.logerrno 111 连不上13 SELinuxprematurely closed 后端退出Nginx 配置nginx -Tnginx -tproxy_http_version 1.1与两个proxy_set_header是否齐全后端监听ss -lntp \grep 8080后端直连curl手工握手直连返回 101 而经 Nginx 502问题必在 Nginx 配置安全策略getenforce、ausearch -m avchttpd_can_network_connect是否为 on进程存活journalctl -u myapp、dmesg -T是否被 OOM 杀掉或反复崩溃重启排查 WebSocket 502 的顺序应该是先看 Nginx 日志拿 errno → 再直连后端做二分 → 最后才动应用代码。日志里的 errno 比任何猜测都可靠而三个必填的代理头部与 SELinux 出站限制覆盖了这类故障中的绝大多数。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

从零开始构建MCP Server:用TaoToken统一Key打通大模型与数据连接 2026/10/2 17:21:01

从零开始构建MCP Server:用TaoToken统一Key打通大模型与数据连接

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
字节Trae AI 配置 API key 与 BaseURL:接入 Anthropic Claude API、gpt-4o、grok、gemini、deepseek 大模型指南 2026/10/2 17:20:54

字节Trae AI 配置 API key 与 BaseURL:接入 Anthropic Claude API、gpt-4o、grok、gemini、deepseek 大模型指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
使用 Rube MCP 自动化 Endorsal 操作:awesome-claude-skills 中 endorsal-automation 技能实战指南 2026/10/2 17:20:48

使用 Rube MCP 自动化 Endorsal 操作:awesome-claude-skills 中 endorsal-automation 技能实战指南

AI 技能AI 插件人工智能工作流自动化 【免费下载链接】awesome-claude-skills A curated list of awesome Claude Skills, resources, and tools for customizing Claude AI workflows 项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-claude-skills 点击…

阅读更多 →
hermes应用:免费且不限流,爱马仕轻松搞定 2026/10/2 17:20:48

hermes应用:免费且不限流,爱马仕轻松搞定

hermes应用:免费且不限流,爱马仕轻松搞定 我给自己搭了一个“永不限流”的AI网关,一分钱没花 主力跑Agnes免费模型,DeepSeek兜底,Hermes Agent负责自动降级。这套方案跑通之后,我再也没见过429。 先说你最关心的问题…

阅读更多 →
欢迎大家能够多多关注我与我的合作者的github 2026/10/2 17:20:42

欢迎大家能够多多关注我与我的合作者的github

alingalingling GitHub

阅读更多 →
devops-exercises Shell 实战:用 for 循环 + `ls`/`du`/`cut` 统计当前目录下所有文件与目录的大小 2026/10/2 17:20:42

devops-exercises Shell 实战:用 for 循环 + `ls`/`du`/`cut` 统计当前目录下所有文件与目录的大小

文档教程DevOps运维 【免费下载链接】devops-exercises Linux, Jenkins, AWS, SRE, Prometheus, Docker, Python, Ansible, Git, Kubernetes, Terraform, OpenStack, SQL, NoSQL, Azure, GCP, DNS, Elastic, Network, Virtualization. DevOps Interview Questions 项目地址&…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉