简体   繁体   English

将Apache WebSocket重定向到Tomcat:mod_proxy和mod_proxy_wstunnel

[英]Apache websocket redirection to Tomcat: mod_proxy and mod_proxy_wstunnel

I am trying to redirect traffic from Apache to Tomcat by using mod_proxy and mod_proxy_wstunnel modules. 我正在尝试使用mod_proxy和mod_proxy_wstunnel模块将流量从Apache重定向到Tomcat。 HTTP traffic is redirected without problems but I am not able to successfully redirect websocket traffic with any configuration I tried so far. HTTP流量可以顺利重定向,但是到目前为止,我无法使用任何配置成功重定向Websocket流量。

I am using Apache 2.4.28 and Tomcat 8.5.13 我正在使用Apache 2.4.28和Tomcat 8.5.13

I must say when I use Tomcat without Apache, websockets works perfectly fine: 我必须说,当我在不使用Apache的情况下使用Tomcat时,websockets可以正常工作:

在此处输入图片说明

The Tomcat connector that works for this configuration is next: 接下来是适用于此配置的Tomcat连接器:

<Connector URIEncoding="UTF-8"
        compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript"
        compression="on"
        compressionMinSize="1024"
        connectionTimeout="20000"
        noCompressionUserAgents="gozilla, traviata"
        port="443"
        protocol="org.apache.coyote.http11.Http11AprProtocol"
        SSLEnabled="true"
        scheme="https"
        secure="true">
        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
        <SSLHostConfig>
            <Certificate certificateKeyFile="/opt/tomcat/cert/privkey.pem"
                         certificateFile="/opt/tomcat/cert/cert.pem"
                         certificateChainFile="/opt/tomcat/cert/chain.pem"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

It's clear until this point. 到目前为止,一切都还很清楚。 Now I start an Apache server in front of Tomcat and the first thing I change is the Tomcat connector like this: 现在,我在Tomcat之前启动一个Apache服务器,而我要做的第一件事就是像这样的Tomcat连接器:

<Connector URIEncoding="UTF-8"
    compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/javascript"
    compression="on"
    compressionMinSize="1024"
    connectionTimeout="20000"
    noCompressionUserAgents="gozilla, traviata"
    port="8080"
    protocol="org.apache.coyote.http11.Http11AprProtocol">
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>

In Apache I successfully load next modules (I have checked they are really loaded): 在Apache中,我成功加载了下一个模块(已检查它们是否已真正加载):

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule ssl_module modules/mod_ssl.so

This is one of the configurations I tried in my vhosts.conf file: 这是我在vhosts.conf文件中尝试的配置之一:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin server@example.com
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
    CustomLog /var/log/httpd/lavnet_access.log combined
    ErrorLog /var/log/httpd/lavnet_error.log

    SSLProxyEngine on
    #websocket
    RewriteEngine on
    RewriteCond %{HTTP:Upgrade} "(?i)websocket"
    RewriteRule ^/(.*)$ wss://www.example.com/$1 [P]
    #rest
    ProxyPass "/" "http://www.example.com:8080/"
    ProxyPassReverse "/" "http://www.example.com:8080/"

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
</VirtualHost>

This is the configuration with best results I have achieved but it's still not working. 这是我获得的最佳结果的配置,但仍无法正常工作。 The log traces in lavnet_error.log seems quite good when I try to establish this connection: 当我尝试建立此连接时,lavnet_error.log中的日志跟踪看起来非常不错:

[Tue Oct 10 16:46:39.014980 2017] [proxy:debug] [pid 10558:tid 47319680603904] proxy_util.c(2209): [client XX.XX.XX.109:11208] AH00944: connecting wss://www.example.com:443/rest/notify/675/fgcw02lm/websocket to www.example.com:443
[Tue Oct 10 16:46:39.016495 2017] [proxy:debug] [pid 10558:tid 47319680603904] proxy_util.c(2418): [client XX.XX.XX.109:11208] AH00947: connected /rest/notify/675/fgcw02lm/websocket to www.example.com:443
[Tue Oct 10 16:46:39.016567 2017] [proxy:debug] [pid 10558:tid 47319680603904] proxy_util.c(2887): AH02824: WSS: connection established with XX.XX.XX.109:443 (*)
[Tue Oct 10 16:46:39.016590 2017] [proxy:debug] [pid 10558:tid 47319680603904] proxy_util.c(3054): AH00962: WSS: connection complete to XX.XX.XX.109:443 (www.example.com)
[Tue Oct 10 16:46:39.016603 2017] [ssl:info] [pid 10558:tid 47319680603904] [remote 217.61.129.109:443] AH01964: Connection to child 0 established (server www.example.com:443)
[Tue Oct 10 16:46:39.026370 2017] [proxy:debug] [pid 10558:tid 47319680603904] proxy_util.c(2171): AH00943: WSS: has released connection for (*)

But this is the error that Chrome shows: 但这是Chrome显示的错误:

在此处输入图片说明 在此处输入图片说明

I have also tried this other configuration: 我也尝试了这种其他配置:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin server@example.com
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
    CustomLog /var/log/httpd/lavnet_access.log combined
    ErrorLog /var/log/httpd/lavnet_error.log
    SSLProxyEngine on

    ProxyPass "/rest/notify/" "wss://www.example.com:8080/rest/notify"
    ProxyPassReverse "/rest/notify/" "wss://www.example.com:8080/rest/notify"

    ProxyPass "/" "http://www.example.com:8080/"
    ProxyPassReverse "/" "http://www.example.com:8080/"

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
</VirtualHost>

But in this case I get a "500 (Internal Server Error)" and also I can see next traces in lavnet_error.log: 但是在这种情况下,我得到“ 500(内部服务器错误)”,并且我还能在lavnet_error.log中看到下一条跟踪记录:

[Tue Oct 10 17:14:14.778824 2017] [proxy:warn] [pid 11924:tid 47694559057664] [client XX.XX.XXX.189:11665] AH01144: No protocol handler was valid for the URL /rest/notify/info (scheme 'wss'). If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule., referer: https://www.example.com/equipment-command-panel/8287/8482

I have tried many configurations but I cannot get this to work. 我已经尝试了许多配置,但是无法正常工作。 I hope you can help me. 我希望你能帮助我。

Thanks. 谢谢。

After many trials I have finally solved it. 经过多次试验,我终于解决了。 Next is the working configuration in case anyone needs it: 接下来是工作配置,以防有人需要:

This is the vhost.conf file of Apache: 这是Apache的vhost.conf文件:

<VirtualHost *:443>
    ServerName www.example.com
    ServerAdmin admin@example.com
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" combined
    CustomLog /var/log/httpd/lavnet_access.log combined
    ErrorLog /var/log/httpd/lavnet_error.log

    ProxyPreserveHost On
    ProxyPass / http://www.example.com:8080/
    ProxyPassReverse / http://www.example.com:8080/
    ProxyRequests Off
    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule .* ws://www.example.com:8080%{REQUEST_URI} [P]

    SSLEngine on
    SSLCertificateFile    /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem
</VirtualHost>

And this one the connector defined in server.xml in Tomcat: 这是Tomcat中server.xml中定义的连接器:

<Connector URIEncoding="UTF-8"
    connectionTimeout="20000"
    port="8080"
    protocol="org.apache.coyote.http11.Http11AprProtocol">
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
</Connector>

Thanks. 谢谢。

The accepted solution works in single instance. 接受的解决方案在单个实例中起作用。 But I have cluster with multiple servers and I have load balancer with mod_jk module. 但是我有多个服务器的群集,并且我有带有mod_jk模块的负载均衡器。 In this case after hours of searching I could find a solution to resolve my problem. 在这种情况下,经过数小时的搜索,我可以找到解决问题的解决方案。 In mod_jk the name of server appended to end of JSESSIONID like this: JSESSIONID=25B9813E079BA3543C242438FD74CA84.banana . mod_jk ,将服务器名称附加到JSESSIONID末尾,如下所示: JSESSIONID=25B9813E079BA3543C242438FD74CA84.banana

So I could write a rule to proxy the websocket request to the proper server with the bellow code: 因此,我可以编写一条规则,使用以下代码将websocket请求代理到适当的服务器:

SSLProxyEngine On
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteCond %{HTTP_COOKIE} (^|;\ *)JSESSIONID=.*\.(.+?)(?=;|$) [NC]
RewriteRule .* wss://%2:8443%{REQUEST_URI} [P]

As you see in the last RewriteCond I write a regex which find the name of server in the second regex group. 如您在上一个RewriteCond所看到的,我编写了一个正则表达式,该表达式在第二个正则表达式组中找到服务器的名称。 So I write a proxy that route the request to wss://%2:8443%{REQUEST_URI} which is the correct server. 因此,我编写了一个代理,将请求路由到wss://%2:8443%{REQUEST_URI} ,这是正确的服务器。

ps: Don't forget to add server names and IP to /etc/hosts ps:别忘了将服务器名称和IP添加到/etc/hosts

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

相关问题 在Apache mod_proxy_wstunnel后面使用go-websocket - Using go-websocket behind Apache mod_proxy_wstunnel 带有Apache mod_proxy_wstunnel的Websocket到带有javax.servlet.request.X509的tomcat - Websocket with apache mod_proxy_wstunnel to tomcat with javax.servlet.request.X509Certificate Apache / 2.4.18(Ubuntu)mod_proxy_wstunnel - Apache/2.4.18 (Ubuntu) mod_proxy_wstunnel 如何在Raspberry Pi(Backport mod_proxy_wstunnel)上将mod_proxy_wstunnel添加到Apache2 2.2 - How to add mod_proxy_wstunnel to Apache2 2.2 on Raspberry Pi (Backport mod_proxy_wstunnel) WebSockets 和 Apache 代理:如何配置 mod_proxy_wstunnel? - WebSockets and Apache proxy : how to configure mod_proxy_wstunnel? apache 2.4.6 reverseeproxy mod_proxy_wstunnel for secure websocket wss://失败 - apache 2.4.6 reverseproxy mod_proxy_wstunnel for secure websocket wss:// fails 在Apache 2.4.x上配置mod_proxy_wstunnel - configure mod_proxy_wstunnel on apache 2.4.x mod_proxy_wstunnel-Mac OS X 10.11.6,Apache 2.4.18 - mod_proxy_wstunnel - Mac OS X 10.11.6, Apache 2.4.18 WebSocket握手期间出错:缺少“升级”标头(Apache 2.4 + mod_proxy_wstunnel) - Error during WebSocket handshake: 'Upgrade' header is missing (Apache 2.4 + mod_proxy_wstunnel) 如何在CentOS上的Apache 2.2上设置mod_proxy_wstunnel - How to set up mod_proxy_wstunnel on Apache 2.2 on CentOS
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM