WebSockets和Apache代理:如何配置mod_proxy_wstunnel?

Bas*_*asj 77 apache proxy websocket node.js socket.io

我有 :

  1. Apache(v2.4)在我的服务器的端口80上www.domain1.com,启用了mod_proxymod_proxy_wstunnel

  2. node.js + socket.io 在同一服务器的端口3001上.

www.domain2.com由于此处描述的方法,访问(使用端口80)重定向到2 . 我在Apache配置中设置了这个:

<VirtualHost *:80>
    ServerName www.domain2.com
    ProxyPass / http://localhost:3001/
    ProxyPassReverse / http://localhost:3001/
    ProxyPass / ws://localhost:3001/
    ProxyPassReverse / ws://localhost:3001/
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

除了websocket部分之外,它适用于所有内容:ws://...不会像代理那样传输.

当我访问该页面时www.domain2.com,我有:

Impossible to connect ws://www.domain2.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.
Run Code Online (Sandbox Code Playgroud)

问题:如何使Apache代理也成为WebSockets?

Bas*_*asj 136

由于这个话题,我终于设法做到了.

去做:

1)安装Apache 2.4(不适用于2.2),并执行:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel
Run Code Online (Sandbox Code Playgroud)

2)nodejs在3001端口上运行

3)在Apache配置中执行此操作

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
  RewriteCond %{QUERY_STRING} transport=websocket    [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]

  ProxyPass / http://localhost:3001/
  ProxyPassReverse / http://localhost:3001/
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

注意:如果在使用websockets的同一服务器上有多个服务,则可能需要执行此操作以将它们分开.

  • 如何从 443 wss 转发到 ws ?rewritecond 会改变吗? (5认同)
  • 这样做时,我的ws://路由仍然会得到502坏网关.在Ubuntu 14.04上运行Apache 2.4 (3认同)
  • 这是可行的,因为所有 HTTP 流量也会被转发,但如果您只想转发套接字流量,请注意 Socket.io 通过 HTTP 轮询请求开始通信。更多信息[此处](http://stackoverflow.com/a/41685748/4080966)。 (2认同)
  • 条件 `RewriteCond %{QUERY_STRING} Transport=websocket [NC]` 无法正常工作。建议改用 `RewriteCond %{HTTP:Upgrade} =websocket [NC]`。 (2认同)

cda*_*uth 82

您也可以按HTTP标头过滤,而不是按URL过滤.此配置适用于任何使用websockets的Web应用程序,如果它们不使用socket.io:

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*)           http://localhost:3001/$1 [P,L]

  ProxyPassReverse / http://localhost:3001/
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)


Ser*_*gey 17

可能会有用.只是所有查询都通过ws发送到节点

<VirtualHost *:80>
  ServerName www.domain2.com

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)


Eri*_*ans 12

从Socket.IO 1.0(2014年5月)开始,所有连接都以HTTP轮询请求开始(此处有更多信息).这意味着除了转发WebSocket流量之外,您还需要转发任何transport=pollingHTTP请求.

下面的解决方案应该正确地重定向所有套接字流量,而不重定向任何其他流量.

  1. 启用以下Apache2 mods:

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在*.conf文件中使用这些设置(例如/etc/apache2/sites-available/mysite.com.conf).我已经包含了解释每件作品的评论:

    <VirtualHost *:80>
        ServerName www.mydomain.com
    
        # Enable the rewrite engine
        # Requires: sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
        # In the rules/conds, [NC] means case-insensitve, [P] means proxy
        RewriteEngine On
    
        # socket.io 1.0+ starts all connections with an HTTP polling request
        RewriteCond %{QUERY_STRING} transport=polling       [NC]
        RewriteRule /(.*)           http://localhost:3001/$1 [P]
    
        # When socket.io wants to initiate a WebSocket connection, it sends an
        # "upgrade: websocket" request that should be transferred to ws://
        RewriteCond %{HTTP:Upgrade} websocket               [NC]
        RewriteRule /(.*)           ws://localhost:3001/$1  [P]
    
        # OPTIONAL: Route all HTTP traffic at /node to port 3001
        ProxyRequests Off
        ProxyPass           /node   http://localhost:3001
        ProxyPassReverse    /node   http://localhost:3001
    </VirtualHost>
    
    Run Code Online (Sandbox Code Playgroud)
  3. 我已经添加了一个额外的部分用于路由/node流量,我觉得很方便,请参阅此处了解更多信息.


Ott*_*sen 7

在这些答案的帮助下,我终于使用这个Apache2站点配置在使用Ubuntu Mate和Apache2的Raspberry Pi上运行Node-RED的反向代理:

<VirtualHost *:80>
    ServerName nodered.domain.com
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://localhost:1880/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://localhost:1880/$1 [P,L]
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

我还必须启用这样的模块:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
Run Code Online (Sandbox Code Playgroud)


Ort*_*ier 7

对运行静态、休息和 websocket 内容的 spring 应用程序执行以下操作。

Apache 用作以下 URI 的代理和 SSL 端点:

  • /app → 静态内容
  • /api → REST API
  • /api/ws → websocket

阿帕奇配置

<VirtualHost *:80>
    ServerName xxx.xxx.xxx    

    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    <Proxy *>
         Require all granted
    </Proxy>

    RewriteEngine On

    # websocket 
    RewriteCond %{HTTP:Upgrade}         =websocket                      [NC]
    RewriteRule ^/api/ws/(.*)           ws://localhost:8080/api/ws/$1   [P,L]

    # rest
    ProxyPass /api http://localhost:8080/api
    ProxyPassReverse /api http://localhost:8080/api

    # static content    
    ProxyPass /app http://localhost:8080/app
    ProxyPassReverse /app http://localhost:8080/app 
</VirtualHost>
Run Code Online (Sandbox Code Playgroud)

我对 SSL 配置使用相同的 vHost 配置,无需更改任何与代理相关的内容。

弹簧配置

server.use-forward-headers: true
Run Code Online (Sandbox Code Playgroud)


Leo*_*eon 7

对我来说,在httpd.conf中添加以下一行(粗体行)后,它就可以工作。


<VirtualHost *:80>
    ServerName: xxxxx

    #ProxyPassReverse is not needed
    ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>
Run Code Online (Sandbox Code Playgroud)

CentOS上的Apache版本是2.4.6。


Bas*_*asj 6

除了主要答案之外:如果同一服务器上有多个使用 websockets 的服务,您可能需要通过使用自定义路径(*) 来分隔它们:

节点服务器:

var io = require('socket.io')({ path: '/ws_website1'}).listen(server);
Run Code Online (Sandbox Code Playgroud)

客户端 HTML:

<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...
Run Code Online (Sandbox Code Playgroud)

阿帕奇配置:

RewriteEngine On

RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]
Run Code Online (Sandbox Code Playgroud)

(*) 注意:使用默认值RewriteCond %{REQUEST_URI} ^/socket.io不会特定于某个网站,并且 websockets 请求会在不同网站之间混合!


Anw*_*lah 5

我的设置:

Apache 2.4.10(运行Debian)NodeJS(版本4.1.1)在端口3000上运行的应用程序在路径/ api/ws上接受WebSockets

如上所述@Basj,请确保启用了a2enmod代理和ws_tunnel.

这是一个解决我的问题的Apache conf文件的屏幕抓图:

在此输入图像描述

希望有所帮助.

  • 你能复制/粘贴而不是截图吗?提前谢谢,它会提高可读性. (5认同)