我有一个正在运行Apache,这只是通过HTTPS访问。 我想从一个运行在同一台机器上的附加服务器应用程序服务的WebSockets,但因为它是不可能的客户到另一个端口443到我们的服务器上的连接,这些WebSocket连接需要通过Apache被代理。
现在,我已经安装的mod_proxy和配置,如下所示:
SSLProxyEngine on
ProxyPass /ws https://127.0.0.1:9001
然而,这并不工作。 我可以连接到https://服务器/ WS在我的浏览器了,但Apache的似乎吞下的WebSockets头的一部分,所以,真正的WebSocket连接不工作。
我怎样才能做到通过Apache服务器隧道我的WebSocket连接?
我找到了工作。
脚本
------------- ---------------- ----------
| Browser |<----->| Apache httpd |<----->| Tomcat |
| | SSL | 2.4.9 | SSL | 7.0.52 |
------------- ---------------- ----------
通过Apache httpd的浏览器的WebSocket,反向代理给Tomcat Web应用程序。 所有SSL前至后。
这里的每件的配置:
浏览器客户端
请注意,在URL中的“/”结尾: wss://host/app/ws/
。 这是必要的,以匹配正确WSS ProxyPass指令(在Apache的配置部进一步向下示出)并防止301重定向到https://host/app/ws
。 也就是说,它是使用https方案而不是后端的WSS方案重定向。
Test Page
<!doctype html>
<body>
<script type="text/javascript">
var connection = new WebSocket("wss://host/app/ws/");
connection.onopen = function () {
console.log("connected");
};
connection.onclose = function () {
console.log("onclose");
};
connection.onerror = function (error) {
console.log(error);
};
</script>
</body>
</html>
阿帕奇的httpd
我使用的Apache httpd的2.4.9,其开箱提供mod_proxy_wstunnel。 但是,使用WSS时提供的mod_proxy_wstunnel.so不支持SSL://方案。 它结束了试图连接到明文后端(Tomcat)的,其失败的SSL握手。 见错误这里 。 所以,你必须遵循的bug报告所建议的修正补丁mod_proxy_wstunnel.c自己。 这是一个简单的3线的变化。
Suggested correction,
314a315
> int is_ssl = 0;
320a322
> is_ssl = 1;
344c346
< backend->is_ssl = 0;
---
> backend->is_ssl = is_ssl;
然后重建模块,并与旧的新mod_proxy_wstunnel.so更换。
构建Apache httpd的
下面是我用来建立在我想要的模块(2.4.9)命令。 你可能并不需要它们。
./configure --prefix=/usr/local/apache --with-included-apr --enable-alias=shared
--enable-authz_host=shared --enable-authz_user=shared
--enable-deflate=shared --enable-negotiation=shared
--enable-proxy=shared --enable-ssl=shared --enable-reqtimeout=shared
--enable-status=shared --enable-auth_basic=shared
--enable-dir=shared --enable-authn_file=shared
--enable-autoindex=shared --enable-env=shared --enable-php5=shared
--enable-authz_default=shared --enable-cgi=shared
--enable-setenvif=shared --enable-authz_groupfile=shared
--enable-mime=shared --enable-proxy_http=shared
--enable-proxy_wstunnel=shared
注意最后一个开关: --enable-proxy_wstunnel=shared
起初,我是不正确地使用--enable-proxy-wstunnel=shared
,这似乎打造精细,但最终当我用得到的.so文件是行不通的。 看到不同? 你要确保使用下划线在"proxy_wstunnel"
,而不是短跑。
Apache的httpd设置
httpd.conf
...
LoadModule proxy_module modules/mod_proxy.so
...
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
...
LoadModule ssl_module modules/mod_ssl.so
...
Include conf/extra/httpd-ssl.conf
...
LogLevel debug
ProxyRequests off
# Note, this is the preferred ProxyPass configuration, and *should* be equivalent
# to the same inline version below, but it does NOT WORK!
#<Location /app/ws/>
# ProxyPass wss://localhost:8443/app/ws
# ProxyPassReverse wss://localhost:8443/app/ws
#</Location>
#<Location /app/>
# ProxyPass https://localhost:8443/app/
# ProxyPassReverse https://localhost:8443/app/
#</Location>
# NOTE: Pay strict attention to the slashes "/" or lack thereof!
# WebSocket url endpoint
ProxyPass /app/ws/ wss://localhost:8443/app/ws
ProxyPassReverse /app/ws/ wss://localhost:8443/app/ws
# Everything else
ProxyPass /app/ https://localhost:8443/app/
ProxyPassReverse /app/ https://localhost:8443/app/
如果你没有看到在上面的配置我注意到,这里要再次重申: 严格注意斜线“/”或缺乏!
此外,如果你看到在你的Apache日志,上面写着一个WSS连接制成然后关闭调试日志报表,有可能你已经mod_reqtimeout启用像我一样,所以一定要确保它没有加载:
#LoadModule reqtimeout_module modules/mod_reqtimeout.so
Tomcat的
假设你的HTTP连接器安装正确,没有太多在Tomcat中进行配置。 虽然在调试的帮助,我认为有必要建立一个$CATALINA_HOME/bin/setenv.sh
是这个样子:
setenv.sh
CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"
这让我看看,我修改了mod_proxy_wstunnel.so是工作或不WSS://。 当它不工作,我的catalina.out的日志文件会显示:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
http-nio-8443-exec-1, SEND TLSv1 ALERT: fatal, description = internal_error
http-nio-8443-exec-1, WRITE: TLSv1 Alert, length = 2
http-nio-8443-exec-1, called closeOutbound()
http-nio-8443-exec-1, closeOutboundInternal()
最后的想法
虽然我使用Apache httpd的2.4.9, 我已经看到了其中mod_proxy_wstunnel的反向移植可应用于版本2.2.x的 。 希望以上我的笔记可以适用于那些旧版本。
如果你不想阿帕奇终止SSL连接(和转发未加密的WebSocket流量),但已经终止了最终目标的WebSocket服务器上的SSL 和 exlusively要使用WSS在进入Apache的WebSocket的流量,然后mod_proxy_connect也许能够刚刚通过的原始交通连接。 不确定。 我会是否可行也有兴趣。
如果上面不成立,这里更多的信息:
- https://serverfault.com/questions/290121/configuring-apache2-to-proxy-websocket
- https://issues.apache.org/bugzilla/show_bug.cgi?id=47485
- http://blog.alex.org.uk/2012/02/16/using-apache-websocket-to-proxy-tcp-connection/
在任何情况下,使用Apache将severly限制有关兼任WebSocket连接数的可扩展性,因为每个WS连接将消耗1个进程/ Apache的线程。
我想安装此https://github.com/kawasima/mod_proxy_websocket 。 希望能帮助到你。