You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HAProxy→Nginx/Passenger→Rails链路WebSocket连接失败排查求助

生产环境Action Cable WebSocket连接失败(404/1006)排查方案

核心问题定位

从Nginx日志提示尝试读取静态文件/opt/webapps/app/current/public/cable来看,Nginx没有将/cable请求转发给Rails应用,而是误将其当作静态资源处理,这是导致404的直接原因。结合你的架构(HAProxy→Nginx/Passenger→Rails),按以下层级逐一排查:

1. 修正Nginx/Passenger配置,确保/cable路由到Rails

在Nginx的server配置块中,添加专门的location /cable规则,覆盖静态文件处理逻辑,强制将请求转发给Rails的Action Cable端点:

server {
    # 其他原有配置...

    # 针对Action Cable的WebSocket请求配置
    location /cable {
        passenger_app_root /opt/webapps/app/current;
        passenger_ruby /path/to/your/ruby; # 替换为实际Ruby路径
        passenger_enabled on;

        # WebSocket升级必需的头信息
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;

        # 禁用Passenger的并发请求限制(避免WebSocket连接被中断)
        passenger_force_max_concurrent_requests_per_process 0;
    }

    # 原有静态文件处理规则(确保在/cable规则之后)
    location ~ ^/assets/ {
        expires 1y;
        add_header Cache-Control public;
        # ...其他静态资源配置
    }
}

注意:location /cable必须放在静态资源处理规则之前,否则Nginx会优先匹配静态文件规则。

2. 验证HAProxy的WebSocket转发配置

HAProxy需要正确识别并转发WebSocket升级请求的头信息,在HAProxy配置中添加以下规则:

frontend https_frontend
    bind *:443 ssl crt /path/to/cert.pem
    # 其他原有配置...

    # 识别WebSocket请求
    acl is_websocket hdr(Upgrade) -i websocket
    acl is_connection_upgrade hdr(Connection) -i upgrade

    # 转发WebSocket必需的头
    reqadd X-Forwarded-Proto:\ https if { ssl_fc }
    reqadd Upgrade:\ websocket if is_websocket
    reqadd Connection:\ upgrade if is_websocket

    # 超时设置(避免WebSocket连接被过早断开)
    timeout client 86400s
    timeout server 86400s

    # 转发到后端Nginx服务器
    default_backend nginx_backend

backend nginx_backend
    # 其他原有配置...
    option http-server-close # 确保HTTP连接正确处理升级
    timeout tunnel 86400s # WebSocket隧道超时

3. 确认Rails端的Action Cable配置

  • 检查config/routes.rb是否已正确挂载Action Cable:
    Rails.application.routes.draw do
      mount ActionCable.server => '/cable'
      # 其他路由...
    end
    
  • 确认config/cable.yml的生产环境配置指向正确的Redis实例:
    production:
      adapter: redis
      url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
      channel_prefix: app_production_cable
    
  • 检查config/environments/production.rb中的Action Cable相关设置:
    config.action_cable.url = "wss://app.host.com/cable"
    config.action_cable.allowed_request_origins = ["https://app.host.com"] # 匹配前端域名
    config.action_cable.disable_request_forgery_protection = false # 保持默认,除非有特殊需求
    

4. 检查Passenger兼容性

确保Passenger版本≥5.0.0(Action Cable需要Passenger支持WebSocket),运行以下命令验证版本:

passenger -v

如果版本过低,升级到最新稳定版:

# 针对Nginx模块的Passenger升级
sudo passenger-install-nginx-module

5. 用curl模拟WebSocket升级请求验证

执行以下命令测试升级流程,观察返回状态码:

curl -i -N \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Host: app.host.com" \
  -H "Origin: https://app.host.com" \
  -H "Sec-WebSocket-Key: SGVsbG8sIHdvcmxkIQ==" \
  -H "Sec-WebSocket-Version: 13" \
  https://app.host.com/cable
  • 如果返回101 Switching Protocols,说明升级成功,问题出在前端配置;
  • 如果仍返回404,继续检查Nginx/HAProxy的路由规则;
  • 如果返回其他错误,根据响应头排查权限或头传递问题。

6. 排除SSO/VPN干扰

  • 确认Okta SSO代理没有过滤Upgrade和Connection头,可联系SSO管理员检查代理规则;
  • 验证VPN是否允许WebSocket流量(虽然443端口通常开放,但部分VPN可能拦截WebSocket握手请求)。

内容的提问来源于stack exchange,提问作者7minutesdead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 20:34:59