【问题标题】:Secure WebSocket Connection through nginx 1.10.3 and LetsEncrypt通过 nginx 1.10.3 和 LetsEncrypt 保护 WebSocket 连接
【发布时间】:2018-08-05 09:37:47
【问题描述】:

因为我不知道为什么我无法通过HTTPS 连接到我的WebSocket 服务器,所以一直在扯头发。

所以,我有一个运行 vue 应用程序的 Express 4 服务器。它使用来自 npm 的 ws 库连接到 WebSocket 服务器。 nginx 是 1.10.3。我使用 LetsEncrypt 来保护它。

当我上网时,我得到(在控制台中):

main.js:12 WebSocket 连接到“wss://play.mysite.com:8443/”失败:连接建立错误:net::ERR_CONNECTION_CLOSED

第 12 行:

window.ws = new WebSocket(${tls}://${window.location.hostname}:${port});`

那是wss://play.mysite.com:8443。它确实在一个子域上。

这是我的nginx 块: 更新:我明白了!

upstream websocket {
    server 127.0.0.1:8443;
}

server {
    root /var/www/play.mysite.com/dist;
    index index.html;

    access_log /var/log/wss-access-ssl.log;
    error_log /var/log/wss-error-ssl.log;

    server_name play.mysite.com www.play.mysite.com;

    location /ws {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }

    listen [::]:443 ssl ipv6only=on default_server; # managed by Certbot
    listen 443 ssl http2 default_server; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/play.mysite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/play.mysite.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

如您所见,我们在https://play.mysite.com 上有子域。我的Express 服务器总是在端口4000 上监听,而我的WebSocket 服务器在生产环境中监听wss / 端口8443

当我查看/var/log/wss-error-ssl.log 时,我得到:

2018/03/01 04:45:17 [错误] 30343#30343: *1 connect() 在连接到上游时失败(111:连接被拒绝),客户端:68.117.172.118,服务器:play.mysite.com ,请求:“GET /static/css/app.67b8cb3fda61e1e2deaa067e29b52040.css HTTP/1.1”,上游:“http://[::1]:4000/static/css/app.67b8cb3fda61e1e2deaa067e29b52040.css”,主机:“play.mysite.com”,引荐来源:“https://play.mysite.com/

那么,我到底做错了什么?

proxy_pass 设置正确。在客户端/服务器上为WebSocket 监听端口8443。什么意思?谢谢。

编辑:是的,我知道端口 8443 正在运行:

root@MySITE:/var/www/play.mysite.com# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 *:https                 *:*                     LISTEN
tcp        0      0 localhost:4000          *:*                     LISTEN
tcp        0      0 localhost:mysql         *:*                     LISTEN
tcp        0      0 *:http                  *:*                     LISTEN
tcp        0      0 *:ssh                   *:*                     LISTEN
tcp6       0      0 [::]:8443               [::]:*                  LISTEN
tcp6       0      0 [::]:https              [::]:*                  LISTEN
tcp6       0      0 [::]:http               [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
udp        0      0 *:bootpc                *:*
udp        0      0 45.76.1.234.vultr.c:ntp *:*
udp        0      0 localhost:ntp           *:*
udp        0      0 *:ntp                   *:*
udp6       0      0 2001:19f0:5:2b9c:54:ntp [::]:*
udp6       0      0 fe80::5400:1ff:fe61:ntp [::]:*
udp6       0      0 localhost:ntp           [::]:*
udp6       0      0 [::]:ntp                [::]:*

【问题讨论】:

  • 这里有几个技术栈。在设置 nginx 之前,您是否尝试过在客户端和服务器之间直接连接 WebSocket?也许你错过了proxy_redirect http://localhost:4000 https://play.mysite.com;。最后,既然你运行了node.js,为什么不试试socket.io呢?
  • 尝试在此行的“升级”中使用大写“U”:proxy_set_header Connection "upgrade"; 标题区分大小写,尽管大多数技术将它们视为不敏感...
  • 你不应该使用window.ws = new WebSocket(${tls}://${window.location.hostname}:${port}/websocket/);
  • @FaizuddinMohammed 是的。仍然 - 错误。

标签: node.js nginx https websocket


【解决方案1】:

TL'DR 为 /websocket 添加第二个位置块并让 javascript 客户端点击 wss://play.mysite.com/websocket

我发现您的 nginx 服务器配置存在一些问题。

  1. Nginx 没有在端口8443 上侦听,但您的 javascript 正在访问wss://play.mysite.com:8443。因此,当 nginx 为 play.mysite.com 域提供端口 44380 时,您的 javascript 正在尝试使用 wss (TLS) 绕过 nginx 并直接命中 NodeJS——尽管我想您打算卸载 SSL到 Nginx 上。 wss 调用必须通过 nginx 才能使 SSL 握手成功。

  2. 您将所有调用传递给localhost:4000。相反,我建议您有两个位置块location / { ... }location /websocket { ... }。这样,在第二个 websocket 位置块中,您可以代理将调用传递给localhost:8443。这需要客户端连接到wss://play.mysite.com/websocket

【讨论】:

  • 这是有道理的。我这样做了,还升级了Upgraded 变量。我用新的 nginx conf 文件更新了我的帖子。同样的错误。我相信。我还更新了client 端以连接到new WebSocket('wss://play.mysite:8443/websocket')/var/log/wss-error-ssl.log 日志。
  • 客户端不应使用 8443 端口,请尝试从 URL 中删除 :8443
  • Nginx conf 基本上是在说:“代理端口 443 上的传入连接,位置匹配 /websocketlocalhost:8443。”这就是我们不需要从客户端定义备用端口 8443 的原因。而是让 wss 协议默认为 443——nginx 正在监听的端口。
  • 还要确保删除location /websocket/ { 块上的尾部斜杠。
  • 酷!很高兴我们把它整理好了。尽情享受您的项目吧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-07
  • 2020-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-17
相关资源
最近更新 更多