How to configure apache proxy for Meteor / SockJS and WebSocket?

I have an apache proxy for meteor applications, and apache and meteor on two separate machines. I need this, since apache has to serve many real websites, and it would be nice to install a meteor application on this computer due to its limited resources.

However, WebSocket handshaking does not work with a 400 response code "Can only be updated on websocket" if I try to connect from the outside through a proxy. Everything works fine when I connect from the local network directly to the meteor machine. When the WebSocket is down, SockJS / Meteor returns to XHR, but unfortunately this causes some errors in the application in question. So I really need WebSocket to work in most cases.

I installed a fix for my apache installation with the patch mentioned here: https://stackoverflow.com/a/2206772/2326322: It all went well, but nothing changed ...

My apache proxy directives are currently as follows:

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/ 

And I even know what causes the problem. Apache proxy works with header. The original request header of the package in question leaving my machine is as follows:

 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 

So far, the packet is being forwarded from the apache proxy as follows:

 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 

So, the “Update” is deleted, and the “Connection” is changed, and therefore, handshaking with websocket is not performed. Now I could always put "Upgrade" in the "websocket" using the RequestHeader directive. However, this is not so, and I assume that it will cause other problems, and therefore I was wondering if there is a real solution to this problem? Or is this a patch from https://stackoverflow.com/a/2129608/2121/2121321_01.h needs to be addressed, and something went wrong on my part, applying it?

From what I read, switching to nginx could make this setup easier. I will consider this, but whenever possible, I would like to do it with apache, since nginx would complicate other things and cost me a lot of time.

+7
apache proxy websocket meteor sockjs
source share
5 answers

We use this for Apache and the SockJS application behind Apache. Apache runs the WebSocket proxy automatically, but you must rewrite the scheme to ws, otherwise it will roll back to XHR. But only if the connection is a WebSocket handshake. Adding the following will fix your problem :) (note: change localhost:3000 match your own backend URL).

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

This answer is based on Fatih's answer. Its solution fails for browsers that send a connection request header other than Update, such as keep-alive, Upgrade. This was for me with Firefox 42.

To solve the problem for Firefox, modify apache RewriteCond as follows:

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

( ^ Update $ becomes Update $ )

I wanted to put this as a comment on Fatih's answers, but I lack the necessary reputation.

+13
source share

After reading several answers, posting on the Meteor forum, and many lawsuits, the entire enchilada that worked for me is presented here. The other answers were somewhat incomplete or at least did not work for me.

I had to do:

 sudo a2enmod proxy_wstunnel 

It was also necessary to add ProxyPass and ProxyPassReverse and change ^ Upgrade $ to Upgrade $ from another SO answer.

 <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> 

then restart apache.

I checked on the console and now there is no error and no xhr requests. Therefore, I assume that it is working correctly

+8
source share

I'm sorry that I cannot provide you with a direct answer with apache instructions, but since you mentioned nginx and the fact that it is complicated, I would like to weigh with an alternative that actually uses nginx but protects you from all the difficulties.

The tutorial https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial will go through the steps to configure Phusion Passenger with or without nginx (it uses nginx inside anyway) to deploy Meteor with several instances that can scale to use all the cores on your server.

It is as simple as:

 $ cd meteor-app-directory $ mkdir public tmp $ passenger start 
+1
source share

Fatih-Arslan's response with the Derwiwie amendment worked like a charm. One thing I had to use was to install wss instead of ws, because my service only works in https.

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

All Articles