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

时间:2014-12-17 13:05:21

标签: node.js apache proxy websocket socket.io

我有:

  1. Apache(v2.4)位于我www.domain1.com服务器的端口80上, mod_proxy {{3} } 已启用

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

  3. 通过mod_proxy_wstunnel,访问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?

12 个答案:

答案 0 :(得分:124)

由于this topic,我终于成功了。

TODO:

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

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2)在端口3001上运行nodejs

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>

注意:如果在使用websockets的同一台服务器上有多个服务,您可能希望do this将它们分开。

答案 1 :(得分:75)

您也可以按HTTP标头过滤,而不是按网址过滤。此配置适用于任何使用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>

答案 2 :(得分:15)

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

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

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

答案 3 :(得分:12)

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

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

  1. 启用以下Apache2 mods:

    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流量,有关详细信息,请参阅here

答案 4 :(得分:7)

在这些答案的帮助下,我终于得到了在Raspberry Pi上运行的Node-RED的反向代理,Ubuntu Mate和Apache2工作,使用这个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

答案 5 :(得分:5)

我的设置:

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

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

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

enter image description here

希望有所帮助。

答案 6 :(得分:5)

对我来说,在httpd.conf中仅添加一行(如下所示)(粗体行)即可。


<VirtualHost *:80>
    ServerName: xxxxx

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

Apache的CentOS版本是2.4.6。

答案 7 :(得分:2)

针对运行静态,静态和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配置,无需更改与代理相关的任何内容。

Spring配置

server.use-forward-headers: true

答案 8 :(得分:1)

除了主要答案:如果您在使用websockets的同一台服务器上有多个服务,您可能希望使用custom path将它们分开来(*):

节点服务器:

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请求会在不同的网站之间混淆!

答案 9 :(得分:0)

对于&#34;民意调查&#34;运输。

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('/');

答案 10 :(得分:0)

使用此链接获取ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

的完整性解决方案

你必须在下面做一步..

获得/ etc / apache2 / mods-available

步骤1 ...

使用以下命令启用模式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”,我们的war文件放在tomcat中,tomcat为aps提供“ws”。 谢谢

我的配置

ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid = 4 =已连接

答案 11 :(得分:0)

TODO:

  1. 安装了Apache 2.4(不适用于2.2),a2enmod proxya2enmod proxy_wstunnel.load

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

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>