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

时间:2014-02-25 01:20:57

标签: apache proxy websocket meteor sockjs

我有一个apache代理用于流星应用程序,apache和meteor在两台独立的机器上。我需要这样,因为apache必须服务于很多真实的网站,因为资源有限,在这台机器上安装流星应用程序并不是一个好主意。

然而,如果我尝试通过代理从外部连接,则WebSocket握手失败,响应代码为400“只能升级到websocket”。当我从局域网内直接连接到流星机器时,一切正常。 当WebSocket失败时,SockJS / Meteor会重新回到XHR,但不幸的是,这会在应用程序中出现一些错误。所以我真的需要WebSocket才能在大多数情况下工作。

我使用此处提到的补丁修补了我的apache安装:https://stackoverflow.com/a/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://stackoverflow.com/a/16998664的补丁应该解决的问题,并且在我应用它时会出现问题?

从我所读到的切换到nginx可以使这个设置更容易。我会考虑这个但是在可能的情况下我想用apache做这个,因为nginx会让其他东西变得更复杂并且花费我很多时间。

5 个答案:

答案 0 :(得分:17)

我们将此用于Apache和Apache背后的SockJS应用程序。 Apache正在自动执行WebSocket代理,但您必须将该方案重写为ws,否则它将回退到XHR。但只有连接是WebSocket握手。添加以下内容将解决您的问题:)(注意:相应地将localhost:3000更改为您自己的后端网址。

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

答案 1 :(得分:12)

这个答案是基于法提赫的回答。对于发送连接请求标头而不是&#34;升级&#34;的浏览器,他的解决方案失败了,例如&#34; keep-alive,Upgrade&#34;。 Firefox 42就是这种情况。

要解决Firefox的问题,请按如下方式更改apache RewriteCond:

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

^升级$ 变为升级$

我想把此作为对法​​提赫答案的评论,但我缺乏必要的声誉。

答案 2 :(得分:8)

在阅读了几个答案之后,在Meteor论坛上发帖,并在这里进行了大量试验,这对我来说是完整的辣酱玉米饼馅。其他答案有点不完整,或者至少对我不起作用。

我必须这样做:

sudo a2enmod proxy_wstunnel 

还必须添加一个ProxyPass和ProxyPassReverse并将^升级$更改为另一个SO答案的升级$。

<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请求。所以我认为它正常工作

答案 3 :(得分:1)

我希望我能用apache说明直接回复你,但既然你已经提到了nginx而事实是,它很难配置,我想用一个实际使用nginx的替代品来衡量保护您免受所有复杂情况的影响。

https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial上的教程介绍了使用或不使用nginx设置Phusion Passenger的步骤(无论如何都在内部使用nginx)进行多实例生产Meteor部署,可以扩展以利用所有核心你的服务器。

这很简单:

$ cd meteor-app-directory
$ mkdir public tmp
$ passenger start

答案 4 :(得分:0)

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]