【问题标题】:WebSockets and Apache proxy: how to configure mod_proxy_wstunnel?WebSockets 和 Apache 代理:如何配置 mod_proxy_wstunnel?
【发布时间】:2015-02-16 01:00:41
【问题描述】:

我有:

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

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

访问www.domain2.com(使用端口80)重定向到2。感谢the method described here。我已经在 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?

【问题讨论】:

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


    【解决方案1】:

    感谢this topic,我终于成功了。

    待办事项:

    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>
    

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

    【讨论】:

    • FWIW,CentOS 7.1 中的 Apache 2.4 有 this bug 因此 rewrite 不会识别 ws:// 协议,并在发送子请求之前添加域。您可以通过将 [P]roxy 标志更改为 [R]edirect 来测试自己。
    • 在执行此操作时,我的 ws:// 路由仍然得到 502 bad gateway。在 Ubuntu 14.04 上运行 Apache 2.4
    • 这是有效的,因为所有的 HTTP 流量都在被转发,但是如果你只想转发你的套接字流量,请注意 Socket.io 使用 HTTP 轮询请求开始通信。更多信息here.
    • 如何从 443 wss 转发到 ws ? rewritecond 会改变吗?
    • 条件RewriteCond %{QUERY_STRING} transport=websocket [NC] 无法正常工作。建议改用RewriteCond %{HTTP:Upgrade} =websocket [NC]
    【解决方案2】:

    除了按 URL 过滤外,您还可以按 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>
    

    【讨论】:

    • 这对我来说很好,但我正在代理一个子路径,我发现添加 ^ 锚点很重要,因为正则表达式正在寻找一个子字符串。例如。 RewriteRule ^[^/]*/foo/(.*) http://${FOO_HOST}/$1 [P,L] (否则 /bar/foo 也会被定向到与 /foo 相同的地方)
    • 这个配置在阿里巴巴云上效果最好。此外,它将修复错误 net::ERR_RESPONSE_HEADERS_TRUNCATED" 希望有人觉得这很有用。
    • 使用 SignalR,我可以说,这对我最有效 +1 谢谢
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

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

      1. 启用以下 Apache2 模组:

        sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
        
      2. 在您的 *.conf 文件中使用这些设置(例如 /etc/apache2/sites-available/mysite.com.conf)。我已经包含了 cmets 来解释每个部分:

        <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 了解更多信息。

      【讨论】:

      • 这非常适合我。请注意,如果您的请求来自根以外的 URL,您可以执行例如RewriteRule /path/(.*)
      【解决方案5】:

      对我来说,在 httpd.conf 中添加 仅一行 后它可以工作,如下所示(粗线)。

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

      CentOS 上的 Apache 版本是 2.4.6。

      【讨论】:

        【解决方案6】:

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

          为运行静态、rest 和 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>
          

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

          弹簧配置

          server.use-forward-headers: true
          

          【讨论】:

          【解决方案8】:

          我的设置:

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

          正如@Basj 上面提到的,确保 a2enmod 代理和 ws_tunnel 已启用。

          这是解决我的问题的 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 设置我的应用程序时遇到问题,您介意帮助我吗? (我坐在清漆缓存服务器的顶部)
          • 你能复制/粘贴而不是截图吗?提前感谢您,它将提高可读性。
          【解决方案9】:

          除了主要答案:如果您在使用 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 请求会混淆!

          【讨论】:

            【解决方案10】:

            使用此链接获取 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,我们的 War 文件放在 tomcat 中,tomcat 为ws 服务 apache。 谢谢

            我的配置

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

            【讨论】:

            • 对不起,我不太明白(尤其是你的最后一句话)。您能否改进答案的格式并为不知道您提到的所有内容的人添加详细信息?
            • Tomcat @ArvindMadhukar 是什么?
            【解决方案11】:

            用于“轮询”传输。

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

            【讨论】:

              【解决方案12】:

              待办事项:

              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>
                

              【讨论】:

                【解决方案13】:

                对于 Windows 上的相同问题,只需从 http.conf 中取消注释以下行:

                然后将以下行添加到您的 apache 配置中:

                    LoadModule proxy_module modules/mod_proxy_wstunnel.so
                

                【讨论】:

                  猜你喜欢
                  • 2014-10-09
                  • 1970-01-01
                  • 2016-10-09
                  • 1970-01-01
                  • 2013-10-31
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-07-06
                  • 1970-01-01
                  相关资源
                  最近更新 更多