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


99

我有 :

  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>

它适用于除websocket部分之外的所有内容:ws://...不会像代理服务器那样传输。

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

Impossible to connect ws://www.domain2.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.

问:如何也使Apache代理WebSockets?

Answers:


161

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

去做:

1)安装Apache 2.4(不适用于2.2),然后执行以下操作:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

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>

注意:如果在使用websocket的同一服务器上有多个服务,则可能需要这样做以将它们分开。


FWIW,CentOS 7.1中的Apache 2.4具有此错误,因此重写将无法识别ws://协议,并在发送子请求之前准备好域。您可以通过将[P] roxy标志更改为[R] edirect来测试自己。
Andor

3
这样做时,我的ws://路由仍然会出现502错误的网关。在Ubuntu 14.04上运行Apache 2.4
Alex Muro 2015年

1
之所以可行,是因为所有HTTP通信也都将被转发,但是如果您只想转发套接字通信,请注意Socket.io使用HTTP轮询请求启动通信。更多信息在这里
Erik Koopmans

4
如何从443 wss转发到ws?rewritecond变化吗?
埃尔南Eche

1
条件RewriteCond %{QUERY_STRING} transport=websocket [NC]无法正常工作。建议改为使用RewriteCond %{HTTP:Upgrade} =websocket [NC]
马丁

99

除了通过URL进行过滤之外,您还可以通过HTTP标头进行过滤。此配置适用于所有使用websocket的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>

这对我来说很好用,但是我代理了一个子路径,并且我发现添加^锚很重要,因为正则表达式正在寻找子字符串。例如RewriteRule ^ [^ /] * / foo /(.*)http:// $ {FOO_HOST} / $ 1 [P,L](否则/ bar / foo也将被定向到与/ foo相同的位置)
Steve礼来公司2013年

此配置在阿里云上最有效。此外,它会修复错误净:: ERR_RESPONSE_HEADERS_TRUNCATED”希望有人发现这很有用。
迈克Musni

使用SignalR,我可以说,这个工作对我最好的感谢+1
VojtěchMraz的

18

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

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

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>

谢谢@Sergey。当我仅使用ws引用的直接路径而不是将所有内容都路由到文档根目录时,这对我有帮助。我已经在下面的答案中显示了我所做的事情,以帮助他人。
Anwaarullah 2015年

此答案适用于简单的Web套接字(无socket.io),所以对我来说,这是一个更好的答案
Tomas

太棒了!这立即为我工作,而其他重写和代理尝试都无法解决我的问题。
斯蒂芬

谢谢!!非常适合基本用例,只需使用ws://的简单Web套接字即可
Antonia Blair

16

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

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

  1. 启用以下Apache2 mod:

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
  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>
  3. 我增加了一个/node方便的路由流量部分,请参阅此处以获取更多信息。


1
这对我来说非常有效。请注意,如果您的请求是通过root以外的URL进入的,则可以执行例如RewriteRule /path/(.*)
Rob Gwynn-Jones,

8

在这些答案的帮助下,我最终获得了使用Rapberry Mate和Apache2在Raspberry Pi上运行的Node-RED的反向代理,并使用以下Apache2站点配置:

<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>

我还必须启用以下模块:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

7

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


<VirtualHost *:80>
    ServerName: xxxxx

    #ProxyPassReverse is not needed
    ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>

CentOS上的Apache版本是2.4.6。


5

我的设置:

  • Apache 2.4.10(在Debian上运行)
  • 在端口3000上运行的Node.js(版本4.1.1)应用程序在路径上接受WebSocket /api/ws

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

这是解决了我的问题的Apache配置文件的屏幕截图:

Apache配置

相关部分为文字:

<VirtualHost *:80>
  ServerName *******
  ServerAlias *******
  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/

  <Location "/api/ws">
      ProxyPass "ws://localhost:3000/api/ws"
  </Location>
</VirtualHost>

希望能有所帮助。


我在使用首选URL而不是默认URL设置应用程序时遇到麻烦,您介意帮我吗?(我坐在清漆缓存服务器的顶部)
乔什(Josh

6
您能复制/粘贴而不是截图吗?预先谢谢您,它将提高可读性。
巴斯基

3

对于运行静态,静态和websocket内容的spring应用程序,是否进行了以下操作?

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

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

Apache配置

<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>

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

弹簧配置

server.use-forward-headers: true

使用位置标记来分隔位置,即:<Location / app> ProxyPass localhost:8080 / app ProxyPassReverse localhost:8080 / app </ Location>
CrazyMerlin

2

使用此链接获取适用于ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html的完整解决方案

您只需要执行以下步骤即可。

/etc/apache2/mods-available

第1步

mode proxy_wstunnel.load使用以下命令启用

$a2enmod proxy_wstunnel.load

第2步

/etc/apache2/sites-available

并在虚拟主机中的.conf文件中添加以下行

ProxyPass "/ws2/"  "ws://localhost:8080/"

ProxyPass "/wss2/" "wss://localhost:8080/"

注意:8080表示您是您的tomcat运行端口,因为我们要连接ws放置在tomcat中的War文件和tomcat服务于apache的位置ws。谢谢

我的配置

ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected

抱歉,我不太了解(尤其是您的最后一句话)。您可以改善答案的格式并为不知道您所提全部内容的人添加详细信息吗?
巴吉(Basj)

什么是Tomcat @ArvindMadhukar?
Basj

1

用于“轮询”传输。

Apache方面:

<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /my/path


    ProxyRequests Off

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
    ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io   
</VirtualHost>

客户端:

var my_socket = new io.Manager(null, {
    host: 'mysite.com',
    path: '/my-connect-3001'
    transports: ['polling'],
}).socket('/');

1

除了主要答案:如果在使用websocket的同一台服务器上有多个服务,则可能希望通过使用自定义路径(*)来分隔服务:

节点服务器:

var io = require('socket.io')({ path: '/ws_website1'}).listen(server);

客户端HTML:

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

Apache配置:

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]

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


0

去做:

  1. 已安装Apache 2.4(不适用于2.2),a2enmod proxy并且a2enmod proxy_wstunnel.load

  2. 在Apache配置中执行此操作,
    只需在文件中添加两行,其中8080​​是您的tomcat运行端口

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.