简体   繁体   English

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

[英]WebSockets and Apache proxy : how to configure mod_proxy_wstunnel?

I have :我有 :

  1. Apache (v2.4) on port 80 of my server for www.domain1.com , with mod_proxy and mod_proxy_wstunnel enabled Apache (v2.4) 在我的服务器的端口 80 上为www.domain1.com启用mod_proxymod_proxy_wstunnel

  2. node.js + socket.io on port 3001 of the same server.同一服务器的 3001 端口上的node.js + socket.io

Accessing www.domain2.com (with port 80) redirects to 2. thanks to the method described here .访问www.domain2.com (使用端口 80)重定向到 2. 感谢这里描述的方法 I have set this in the Apache configuration:我已经在 Apache 配置中设置了这个:

<VirtualHost *:80>
    ServerName www.domain2.com
    ProxyPass / http://localhost:3001/
    ProxyPassReverse / http://localhost:3001/
    ProxyPass / ws://localhost:3001/
    ProxyPassReverse / ws://localhost:3001/
</VirtualHost>

It works for everything, except the websocket part : ws://... are not transmitted like it should by the proxy.它适用于所有内容,除了 websocket 部分: ws://...不会像代理那样传输。

When I access the page on www.domain2.com , I have:当我访问www.domain2.com上的页面时,我有:

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

Question: How to make Apache proxy the WebSockets as well?问题:如何让 Apache 也代理 WebSockets?

I finally managed to do it, thanks to this topic . 由于这个话题 ,我终于设法做到了。

TODO: 去做:

1) Have Apache 2.4 installed (doesn't work with 2.2), and do: 1)安装Apache 2.4(不适用于2.2),并执行:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) Have nodejs running on port 3001 2)让nodejs在端口3001上运行

3) Do this in the Apache config 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>

Note: if you have more than one service on the same server that uses websockets, you might want to do this to separate them. 注意:如果在使用websockets的同一服务器上有多个服务,则可能需要执行此操作以将它们分开。

Instead of filtering by URL, you can also filter by HTTP header. 您也可以按HTTP标头过滤,而不是按URL过滤。 This configuration will work for any web applications that use websockets, also if they are not using socket.io: 此配置适用于任何使用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>

May be will be useful. 可能会有用。 Just all queries send via ws to node 只是所有查询都通过ws发送到节点

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

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

As of Socket.IO 1.0 (May 2014), all connections begin with an HTTP polling request (more info here ). 从Socket.IO 1.0(2014年5月)开始,所有连接都以HTTP轮询请求开始( 此处有更多信息)。 That means that in addition to forwarding WebSocket traffic, you need to forward any transport=polling HTTP requests. 这意味着除了转发WebSocket流量之外,您还需要转发任何transport=polling HTTP请求。

The solution below should redirect all socket traffic correctly, without redirecting any other traffic. 下面的解决方案应该正确地重定向所有套接字流量,而不重定向任何其他流量。

  1. Enable the following Apache2 mods: 启用以下Apache2 mods:

     sudo a2enmod proxy rewrite proxy_http proxy_wstunnel 
  2. Use these settings in your *.conf file (eg /etc/apache2/sites-available/mysite.com.conf ). 在* .conf文件中使用这些设置(例如/etc/apache2/sites-available/mysite.com.conf )。 I've included comments to explain each piece: 我已经包含了解释每件作品的评论:

     <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. I've included an extra section for routing /node traffic that I find handy, see here for more info. 我已经为路由/node流量添加了一个额外的部分,我觉得很方便,请参阅此处了解更多信息。

With help from these answers, I finally got reverse proxy for Node-RED running on a Raspberry Pi with Ubuntu Mate and Apache2 working, using this Apache2 site config: 在这些答案的帮助下,我终于使用这个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>

I also had to enable modules like this: 我还必须启用这样的模块:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

For me it works after adding only one line in httpd.conf as below (bold line). 对我来说,它只能在httpd.conf中添加一行 ,如下所示(粗线)。


<VirtualHost *:80>
    ServerName: xxxxx

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

Apache version is 2.4.6 on CentOS. 在CentOS上,Apache版本是2.4.6。

My setup: 我的设置:

  • Apache 2.4.10 (running off Debian) Apache 2.4.10(运行Debian)
  • Node.js (version 4.1.1) App running on port 3000 that accepts WebSockets at path /api/ws Node.js(版本4.1.1)在端口3000上运行的应用程序,它接受路径/api/ws WebSockets

As mentioned above by @Basj, make sure a2enmod proxy and ws_tunnel are enabled. 如上所述@Basj,请确保启用了a2enmod代理和ws_tunnel。

This is a screenshot of the Apache config file that solved my problem: 这是解决我的问题的Apache配置文件的屏幕截图:

Apache配置

The relevant part as text: 相关部分为文字:

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

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

Hope that helps. 希望有所帮助。

Did the following for a spring application running static, rest and websocket content. 对弹簧应用程序执行以下操作是否运行静态,休息和websocket内容。

The Apache is used as Proxy and SSL Endpoint for the following URIs: Apache用作以下URI的代理和SSL端点:

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

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

I use the same vHost config for the SSL configuration, no need to change anything proxy related. 我使用相同的vHost配置进行SSL配置,无需更改任何与代理相关的内容。

Spring configuration 弹簧配置

server.use-forward-headers: true

In addition to the main answer: if you have more than one service on the same server that uses websockets, you might want to do this to separate them, by using a custom path (*): 除了主要答案:如果在使用websockets的同一服务器上有多个服务,您可能希望通过使用自定义路径 (*)将它们分开:

Node server: 节点服务器:

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

Client HTML: 客户端HTML:

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

Apache config: 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]

(*) Note: using the default RewriteCond %{REQUEST_URI} ^/socket.io would not be specific to a website, and websockets requests would be mixed up between different websites! (*)注意:使用默认的RewriteCond %{REQUEST_URI} ^/socket.io不会特定于网站,并且websockets请求将在不同的网站之间混淆!

For the same issue on Windows, just uncomment the below line from http.conf:对于 Windows 上的相同问题,只需从 http.conf 中取消注释以下行:

在此处输入图片说明

Then add the below line to your apache config:然后将以下行添加到您的 apache 配置中:

    LoadModule proxy_module modules/mod_proxy_wstunnel.so

For "polling" transport. 用于“投票”运输。

Apache side: 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>

Client side: 客户端:

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

User this link for perfact solution for ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html 使用此链接获取ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html的 perfact解决方案

You have to just do below step.. 你必须在下面做一步..

Go to /etc/apache2/mods-available 转到/etc/apache2/mods-available

Step...1 步骤1

Enable mode proxy_wstunnel.load by using below command 使用以下命令启用mode proxy_wstunnel.load

$a2enmod proxy_wstunnel.load

Step...2 第2步

Go to /etc/apache2/sites-available 转到/etc/apache2/sites-available

and add below line in your .conf file inside virtual host 并在虚拟主机内的.conf文件中添加以下行

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

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

Note : 8080 mean your that your tomcat running port because we want to connect ws where our War file putted in tomcat and tomcat serve apache for ws . 注意:8080意味着你的tomcat运行端口是因为我们要连接ws ,我们的war文件放在tomcat中,而tomcat为ws提供apache。 thank you 谢谢

My Configuration 我的配置

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

TODO: 去做:

  1. Have Apache 2.4 installed (doesn't work with 2.2), a2enmod proxy and a2enmod proxy_wstunnel.load 安装Apache 2.4(不适用于2.2), a2enmod proxya2enmod proxy_wstunnel.load

  2. Do this in the Apache config 在Apache配置中执行此操作
    just add two line in your file where 8080 is your tomcat running port 只需在文件中添加两行,其中8080​​是您的tomcat运行端口

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM