首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用apache隧道传输安全的websocket连接

使用apache隧道传输安全的websocket连接
EN

Stack Overflow用户
提问于 2012-07-13 17:54:03
回答 2查看 40.6K关注 0票数 21

我有一个只能通过HTTPS访问的Apache正在运行。我想从运行在同一台机器上的另一个服务器应用程序为websocket提供服务,但由于客户端不可能在443以外的其他端口上连接到我们的服务器,因此这些websocket连接需要通过Apache代理。

现在,我已经安装了mod_proxy并进行了如下配置:

代码语言:javascript
复制
SSLProxyEngine on
ProxyPass /ws https://127.0.0.1:9001

然而,这并不起作用。我现在可以在我的浏览器中连接到https://server/ws,但是apache似乎吞噬了websocket头的一部分,所以真正的websocket连接不起作用。

如何通过Apache服务器实现websocket连接的隧道传输?

EN

回答 2

Stack Overflow用户

发布于 2014-04-05 05:58:29

我已经把它弄好了。

场景

代码语言:javascript
复制
-------------       ----------------       ----------
| Browser   |<----->| Apache httpd |<----->| Tomcat |
|           |  SSL  |    2.4.9     |  SSL  | 7.0.52 |
-------------       ----------------       ----------

浏览器WebSocket通过Apache httpd,反向代理到Tomcat中的web应用程序。所有SSL都是从前到后。

下面是每一块的配置:

浏览器客户端

注意url中的尾部"/“:wss://host/app/ws/.有必要匹配正确的wss ProxyPass指令(在Apache config部分下面显示),并防止301重定向到https://host/app/ws。也就是说,它在后端使用https方案而不是wss方案进行重定向。

测试页面

代码语言:javascript
复制
<!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>

Apache httpd

我使用的是Apache httpd 2.4.9,它提供了mod_proxy_wstunnel.但是,在使用wss://方案时,提供的mod_proxy_wstunnel.so不支持SSL。它最终尝试以明文形式连接到后端(Tomcat),这导致SSL握手失败。请参见bug here。因此,您必须按照错误报告中的建议更正来为mod_proxy_wstunnel.c打补丁。这是一个简单的3行代码的更改。

代码语言:javascript
复制
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)命令。您可能并不需要全部使用它们。

代码语言:javascript
复制
./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

代码语言:javascript
复制
...
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,因此请确保它未加载:

代码语言:javascript
复制
#LoadModule reqtimeout_module modules/mod_reqtimeout.so

Tomcat

假设您的HTTP连接器设置正确,那么在tomcat中不需要配置太多东西。不过,为了帮助调试,我发现创建如下所示的$CATALINA_HOME/bin/setenv.sh非常有用:

setenv.sh

代码语言:javascript
复制
CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"

这使我可以查看我修改的mod_proxy_wstunnel.so是否对wss://起作用。当它不工作时,我的catalina.out日志文件将显示:

代码语言:javascript
复制
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,I've seen where backports of mod_proxy_wstunnel can be applied to versions 2.2.x。希望我上面的注释可以应用于那些较旧的版本。

票数 29
EN

Stack Overflow用户

发布于 2012-07-13 18:40:45

如果您不希望Apache终止SSL连接(并转发未加密的WebSocket通信),但在最终目标WebSocket服务器上终止了SSL,并且想要对进入Apache的WebSocket通信使用WSS,那么WSS也许能够仅通过原始通信进行连接。不确定。如果它能工作,我也会很感兴趣。

如果以上不成立,这里有更多信息:

在任何情况下,使用Apache都会严重限制并发服务的WebSocket连接数量的可伸缩性,因为每个WS连接将消耗Apache上的一个进程/线程。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11468154

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档