如何为Meteor/SockJS和WebSocket设置Apache代理?

9
我有一个Apache代理用于Meteor应用程序,而Apache和Meteor位于两台不同的机器上。我需要这样做是因为Apache必须服务于许多真实的网站,如果在此机器上安装Meteor应用程序会因其资源有限而不明智。
然而,如果我尝试通过代理从外部连接时,WebSocket握手将失败,响应代码为400“仅能升级到WebSocket”。当我直接从局域网连接到Meteor机器时,一切正常。
当WebSocket失败时,SockJS/Meteor会回退到XHR,但不幸的是,这会引起所涉及的应用程序中的一些错误。因此,在大多数情况下,我真的需要WebSocket正常工作。
我使用此处提到的补丁修复了我的Apache安装:https://dev59.com/kWYq5IYBdhLWcg3weQgy#16998664。看起来进展顺利,但没有任何改变...
我的Apache代理指令目前如下:
ProxyRequests Off
ProxyPreserveHost On
ModPagespeed Off
<proxy>
Order deny,allow
Allow from all
</proxy>
ProxyPass / http://10.0.2.6:3000/
ProxyPassReverse / http://10.0.2.6:3000/

我甚至知道什么导致了这个问题。Apache代理与头部进行操作。离开我的机器的问题数据包的原始请求头看起来像这样:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent

当数据包从Apache代理程序转发时,情况如下:

GET /sockjs/430/minw4r_o/websocket HTTP/1.1
Host: example.com
Origin: http://example.com
Pragma: no-cache
Cache-Control: no-cache
Sec-WebSocket-Key: myKey
Sec-WebSocket-Version: 13
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits, x-webkit-deflate-frame
User-Agent: My Agent
X-Forwarded-For: 24.xxx.xxx.xxx
X-Forwarded-Host: example.com
X-Forwarded-Server: example.com
Connection: Keep-Alive

因此,“升级”被删除,“连接”被改变,因此Websocket握手失败。现在,我可以尝试使用RequestHeader指令将“Upgrade”始终设置为“websocket”。但是这不太对,我猜这会带来其他问题,因此我想知道是否有真正的解决方案?或者这是https://dev59.com/kWYq5IYBdhLWcg3weQgy#16998664补丁应该解决的问题,但我的应用出了问题?
根据我所读的,切换到nginx可能会使这种设置更容易。我会考虑这个建议,但如果可能的话,我想使用apache,因为nginx会使其他事情更加复杂并花费我很多时间。
5个回答

22

我们将其用于 Apache 和在 Apache 后面的 SockJS 应用程序。Apache 会自动代理 WebSocket,但您必须将协议重写为“ws”,否则它会退回到 XHR。但仅当连接是 WebSocket 握手时才需要这样做。添加以下内容即可解决您的问题 :)(注意:根据您自己的后端 URL 更改 localhost:3000。)

RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

1
这是唯一的解决方案。所有其他答案都无法为我工作;它们只会导致对SockJS的请求超时。这是唯一可以自动透明地为所有Web套接字工作的答案。 - Léo Lam
2
我应该把这段代码放在哪里? - Dimitri Kouvdis
这是完整的.htaccess文件吗(我的共享主机提供商没有全局配置),还是我需要添加一些行,例如带有http协议的RewriteRule? - rriemann
这个答案在Firefox上不能正常工作,请参考@derwiwie的答案获取更灵活的版本。 - Duncan

19
基于 Fatih 的回答,此解答方式对于发送 "keep-alive, Upgrade" 等其他升级连接请求头的浏览器将失败,如 Firefox 42。为了解决这个问题,请按以下方式更改 apache RewriteCond。
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

(^Upgrade$ 变成 Upgrade$)

我想把这个作为评论留给Fatih的回答,但是我没有足够的声望。


我在<Location>指令中使用了这个片段,最终它运行良好! - Adriano P
我的英雄 - 不知道为什么Chrome可以工作但Firefox不能。从^Upgrade$中删除^对我有帮助。虽然我不太了解语法,但还是谢谢! :) - user1274820
太棒了,花了我2个小时才找到这个代码片段!它完美地运行了。 - user230910

10

在阅读了几篇答案、在Meteor论坛上发布了帖子并进行了许多尝试后,我找到了适合我的完整步骤。其他答案不太完整,或者至少对我没用。

我需要执行以下步骤:

sudo a2enmod proxy_wstunnel 

还必须添加ProxyPass和ProxyPassReverse,并根据另一个SO答案将^Upgrade$更改为Upgrade$。

<VirtualHost *:80>
    ServerName  some-domain.com

    RewriteEngine on
    RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
    RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
    RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]

    ProxyPass / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

</VirtualHost>

然后重新启动Apache。

我在控制台上检查了一下,现在没有错误也没有xhr请求。所以我认为它正常工作了。


我的英雄 - 不知道为什么Chrome可以工作但Firefox不能。从^Upgrade$中删除^对我有帮助。虽然我不太了解语法,但还是谢谢! :) - user1274820

1

Fatih-Arslan的答案加上Derwiwie的修正非常有效。 我需要做的一件事是使用wss替换ws,因为我的服务只能在https中使用。

RewriteEngine on  
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]  
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]  
RewriteRule .* wss://localhost:3000%{REQUEST_URI} [P]

1
我希望能够为您提供一份直接的apache指令回复,但是由于您提到了nginx并且事实上它很难配置,我想提供一个替代方案,它实际上使用了nginx但是可以让您免除所有的复杂性。 https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial的教程说明了如何设置Phusion Passenger,用于多实例生产Meteor部署,可以扩展到服务器的所有核心,无论是否使用nginx(它内部使用了nginx)。
它非常简单:
$ cd meteor-app-directory
$ mkdir public tmp
$ passenger start

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接