Nginx反向代理WebSocket超时

时间:2018-08-29 13:01:22

标签: nginx websocket nginx-reverse-proxy

我正在wowza应用程序中使用java-websocket满足我的websocket需求,并在ssl中使用了nginx,将请求代理到J​​ava。

问题是服务器端恰好在1小时后似乎断开了连接。客户端甚至都不知道它断开了很长时间。我不想只是调整nginx上的超时,我想了解为什么连接会被终止,因为套接字会像往常一样发挥作用,直到没有出现为止。

编辑: 忘记发布配置:

location /websocket/ {
    proxy_set_header        X-Real-IP       $remote_addr;
    proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    include conf.d/proxy_websocket;
    proxy_connect_timeout 1d;
    proxy_send_timeout 1d;
    proxy_read_timeout 1d;
}

其中包括配置:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_pass                      http://127.0.0.1:1938/;
  • Nginx / 1.12.2
  • CentOS Linux版本7.5.1804(核心)
  • Java WebSocket 1.3.8(GitHub

2 个答案:

答案 0 :(得分:2)

超时可能来自客户端,nginx或后端。当您说正在“服务器端”被切断时,我的意思是您已经证明它不是客户端。您的nginx配置看起来不应该为1 day超时,这样就只剩下后端了。

直接测试后端

我的第一个建议是您尝试直接连接到后端并确认问题仍然存在(将nginx移出图片以进行故障排除)。请注意,如果使用浏览器不切实际,则可以使用curl之类的命令行实用程序来执行此操作。这是一个示例测试命令:

time curl --trace-ascii curl-dump.txt -i -N \
  -H "Host: example.com" \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: BOGUS+KEY+HERE+IS+FINE==" \
  http://127.0.0.1:8080

在我的(工作中)情况下,运行上面的示例将无限期保持打开状态(我用Ctrl-C手动停止了),因为curl和我的服务器都未实现超时。但是,当我将其更改为通过nginx作为代理(默认超时为1分钟)时,如下所示,我几乎在1分钟后看到了来自nginx的504响应。

time curl -i -N --insecure \
  -H "Host: example.com" \
  https://127.0.0.1:443/proxied-path
HTTP/1.1 504 Gateway Time-out
Server: nginx/1.14.2
Date: Thu, 19 Sep 2019 21:37:47 GMT
Content-Type: text/html
Content-Length: 183
Connection: keep-alive

<html>
<head><title>504 Gateway Time-out</title></head>
<body bgcolor="white">
<center><h1>504 Gateway Time-out</h1></center>
<hr><center>nginx/1.14.2</center>
</body>
</html>

real    1m0.207s
user    0m0.048s
sys 0m0.042s

其他想法

有人提到尝试proxy_ignore_client_abort,但是除非客户端关闭连接,否则应该没有任何区别。此外,尽管这可能会使内部连接保持打开状态,但我认为它无法保持端到端流的完整性。

您可能需要尝试proxy_socket_keepalive,尽管这需要nginx> = 1.15.6。

最后,WebSocket proxying doc中有一条注释提示了一个好的解决方案:

  

或者,可以将代理服务器配置为定期发送WebSocket ping帧以重置超时并检查连接是否仍然有效。

如果您可以控制后端并希望连接无限期保持打开状态,请定期向客户端发送"ping" frames(假设使用了Web浏览器,则无需在客户端进行任何更改)作为规范的一部分实施),无论打开了多长时间或涉及多少中间盒,都应防止由于不活动而导致连接关闭(使proxy_read_timeout不必要)。

答案 1 :(得分:0)

最可能的原因是您对websocket代理的配置需要进行一些调整,但是由于您询问:

  

反向代理服务器面临一些挑战   支持WebSocket。一种是WebSocket是逐跳协议,   因此,当代理服务器拦截来自客户端的升级请求时   需要将自己的升级请求发送到后端服务器,包括   适当的标题。另外,由于WebSocket连接很长   与HTTP使用的典型的短暂连接相反,   反向代理需要允许这些连接保持打开状态,   而不是因为它们似乎闲置而关闭它们。

在处理websocket代理的location指令中,您需要包含标头,这是Nginx提供的示例:

location /wsapp/ {
    proxy_pass http://wsbackend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
}

这现在应该起作用,因为:

  

NGINX支持WebSocket,方法是允许在   客户端和后端服务器。 NGINX发送升级请求   从客户端到后端服务器,升级和连接   标头必须明确设置,如本例所示

我还建议您看看Nginx Nchan module,它可以将Websocket功能直接添加到Nginx中。效果很好。