Apache 反向代理到 NodeJS WebSocket 服务器

时间:2021-05-28 15:55:26

标签: node.js apache websocket reverse-proxy

首先,是的,我查看了其他帖子,例如 thisthis 甚至 this 等。

话虽如此,让我揭露我的情况:

它在 dev-env (localhost) 上完全正常(当然,它不需要任何代理)

我也用这个 curl 命令来确认:

curl 'http://localhost:9021/ws' \
  --http1.1 \
  -H 'Pragma: no-cache' \
  -H 'Sec-WebSocket-Key: W/ZEACBv+gi6xA1JeMaO/A==' \
  -H 'Upgrade: websocket' \
  -H 'Cache-Control: no-cache' \
  -H 'Connection: Upgrade' \
  -H 'Sec-WebSocket-Version: 13'

它连接正常。

当我在远程开发服务器上运行它时,我有这个 Apache 配置:

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName dev.remote.com

  LogLevel warn
  ErrorLog "| /usr/bin/rotatelogs -l /home/user/log/dev.remote.com/error.%Y-%m-%d 86400"
  CustomLog "| /usr/bin/rotatelogs -l /home/user/log/dev.remote.com/access.%Y-%m-%d 86400" combined
  ServerSignature Off

  DocumentRoot /home/user/www/dev.remote.com

  <Directory /home/user/www/dev.remote.com>
    Options -Indexes +FollowSymLinks +MultiViews
    AllowOverride All
    Require all granted
  </Directory>

  <Location />
    Options FollowSymLinks
  </Location>

  #
  # Serve static files directly with Apache
  #

  ProxyPass /public !
  Alias /public /home/user/www/dev.remote.com/public

  <Directory /home/user/www/dev.remote.com/public>
    Options -Indexes +FollowSymLinks +MultiViews
    AllowOverride All
    Require all granted
  </Directory>

  ProxyPass /assets !
  Alias /assets /home/user/www/dev.remote.com/.next/static/assets

  <Directory /home/user/www/dev.remote.com/.next/static/assets>
    Options -Indexes +FollowSymLinks +MultiViews
    AllowOverride All
    Require all granted
  </Directory>

  #
  # Serve the rest with NodeJS/express
  #

  RewriteEngine On
  LogLevel alert rewrite:trace6

  RewriteCond %{HTTP:Connection} upgrade [NC]
  RewriteRule /ws  ws://localhost:9021/ws [P]

  ProxyPreserveHost On
  ProxyRequests off

  # WebSocket server (express) is on port 9021
  ProxyPass /ws  ws://localhost:9021/ws
  ProxyPassReverse /ws  ws://localhost:9021/ws

  # HTTP server (express) is on port 9020
  ProxyPass / http://localhost:9020/
  ProxyPassReverse / http://localhost:9020/

  <Proxy *>
    Require all granted
  </Proxy>


SSLCertificateFile /etc/letsencrypt/live/dev.remote.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/dev.remote.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

这里 2 分:

1. 通过使用先前的 curl 命令通过 ssh 进行测试,我确定 WebSocket 服务器正在远程服务器上工作。它连接起来。

2. 当我尝试从浏览器打开连接时

ws = new WebSocket('wss://dev.remote.com/ws');

mod_rewrite 规则似乎没问题,因为跟踪是这样的:

[Fri May 28 17:37:16.272448 2021] [rewrite:trace2] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] init rewrite engine with requested uri /ws
[Fri May 28 17:37:16.272475 2021] [rewrite:trace3] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] applying pattern '/ws' to uri '/ws'
[Fri May 28 17:37:16.272505 2021] [rewrite:trace4] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] RewriteCond: input='Upgrade' pattern='upgrade' [NC] => matched
[Fri May 28 17:37:16.272513 2021] [rewrite:trace2] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] rewrite '/ws' -> 'ws://localhost:9021/ws'
[Fri May 28 17:37:16.272521 2021] [rewrite:trace2] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] forcing proxy-throughput with ws://localhost:9021/ws
[Fri May 28 17:37:16.272529 2021] [rewrite:trace1] [pid 15772] mod_rewrite.c(477): [client a.b.c.d:63015] a.b.c.d - - [dev.remote.com/sid#6916462d1a20][rid#69164d3530a0/initial] go-ahead with proxy request proxy:ws://localhost:9021/ws [OK]

所以我推断规则是有效的,它实际上是通过代理向 :ws://localhost:9021/ws

发出请求

但是...在 WebSocket 服务器中没有收到连接。 因此,我在 Chrome 上得到了这个:

WebSocket connection to 'wss://dev.remote.com/ws' failed

1 个答案:

答案 0 :(得分:0)

关键是让 proxy_wstunnel mod 处于活动状态 >_<

如果它对任何人有帮助...

cd /etc/apache2/mods-enabled
sudo ln -s ../mods-available/proxy_wstunnel.load

愚蠢的错误,但我太专注于配置,而且是关于启用的模组