Как настроить прокси-сервер apache для Meteor / SockJS и WebSocket?

У меня есть прокси-сервер apache для приложения Meteor, а Apache и Meteor находятся на двух разных машинах. Мне это нужно, так как apache должен обслуживать множество реальных веб-сайтов, и было бы не рекомендуется устанавливать приложение Meteor на этом компьютере из-за его ограниченных ресурсов.

Однако рукопожатие WebSocket не удается с кодом ответа 400 «Можно обновить только до веб-сокета», если я пытаюсь подключиться извне через прокси. Все работает нормально, когда я подключаюсь из локальной сети напрямую к метеорной машине. Когда 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

Таким образом, «Обновление» удаляется, а «Соединение» изменяется, и поэтому рукопожатие веб-сокета не выполняется. Теперь я мог бы попытаться всегда устанавливать «Upgrade» на «websocket» с помощью директивы RequestHeader. Однако это кажется неправильным, и я предполагаю, что это вызовет другие проблемы, поэтому мне было интересно, есть ли реальное решение этой проблемы? Или это то, на что должен обратить внимание патч из https://stackoverflow.com/a/16998664, и что-то пошло не так на моем конце применения Это?

Из того, что я прочитал, переход на nginx может упростить эту настройку. Я подумаю об этом, но по возможности я хотел бы сделать это с помощью apache, поскольку nginx усложнит другие вещи и будет стоить мне много времени.


person Jey DWork    schedule 25.02.2014    source источник


Ответы (5)


Мы используем это для Apache и приложения SockJS за Apache. Apache выполняет прокси-сервер WebSocket автоматически, но вам нужно переписать схему на ws, иначе она откатится к XHR. Но только если соединение представляет собой рукопожатие WebSocket. Добавление следующего исправит вашу проблему :) (примечание: измените localhost:3000 в соответствии с вашим собственным URL-адресом серверной части.

RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^websocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade [NC]
RewriteRule .* ws://localhost:3000%{REQUEST_URI} [P]
person Fatih Arslan    schedule 20.08.2014
comment
Это решение. Все остальные ответы не сработали для меня; они просто приведут к истечению времени ожидания запросов к SockJS. Это единственный ответ, который работает для всех веб-сокетов автоматически и прозрачно. - person Léo Lam; 12.10.2014
comment
Куда мне добавить этот фрагмент? - person Dimitri Kouvdis; 03.06.2015
comment
Это полный файл .htaccess (у моего провайдера общего хоста нет глобальной конфигурации) или я должен добавить несколько строк, например RewrireRule с протоколом http? - person rriemann; 08.12.2015
comment
Этот ответ не работает правильно в Firefox, см. Ответ @ derwiwie для более гибкой версии. - person Duncan; 15.04.2016

Этот ответ основан на ответе Фатиха. Его решение не работает для браузеров, которые отправляют заголовок запроса на соединение, отличный от «Upgrade», например «keep-alive, Upgrade». Так было с Firefox 42.

Чтобы решить эту проблему и для Firefox, измените apache RewriteCond следующим образом:

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

(^ Обновить $ становится Обновить $)

Я хотел сказать это как комментарий к ответу Фатиха, но у меня нет необходимой репутации.

person derwiwie    schedule 19.12.2015
comment
Я использовал этот фрагмент в своей директиве ‹Location›, и он работал хорошо (наконец-то!). - person Adriano P; 07.06.2016
comment
Мой герой - задавался вопросом, почему Chrome работает, а Firefox нет. Удаление ^ из ^Upgrade$ помогло мне. Я недостаточно разбираюсь в синтаксисе, но спасибо! :) - person user1274820; 20.03.2018
comment
Великолепно, прошло более 2 часов, прежде чем я нашел этот фрагмент! Это сработало отлично - person user230910; 08.06.2019

Прочитав несколько ответов, разместив сообщения на форуме Meteor и проведя множество испытаний, вот вся энчилада, которая сработала для меня. Другие ответы были несколько неполными или, по крайней мере, не работали для меня.

Пришлось сделать:

sudo a2enmod proxy_wstunnel 

Также пришлось добавить ProxyPass и ProxyPassReverse и изменить ^ Upgrade $ на Upgrade $ из другого ответа 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. Итак, я предполагаю, что он работает правильно

person pferrel    schedule 28.04.2016
comment
Мой герой - задавался вопросом, почему Chrome работает, а Firefox нет. Удаление ^ из ^Upgrade$ помогло мне. Я недостаточно разбираюсь в синтаксисе, но спасибо! :) - person user1274820; 20.03.2018

Мне жаль, что я не смог предоставить вам прямой ответ с инструкциями apache, но поскольку вы упомянули nginx и факт в том, что его сложно настроить, я хотел бы взвесить альтернативу, которая на самом деле использует nginx, но защищает вас от все сложности.

Учебник по адресу https://github.com/phusion/passenger/wiki/Phusion-Passenger:-Meteor-tutorial содержит пошаговые инструкции по настройке Phusion Passenger с или без nginx (он все равно внутренне использует nginx) для многоэкземплярных производственных развертываний Meteor, которые могут масштабироваться для использования всех ядер на вашем сервере.

Это так же просто, как:

$ cd meteor-app-directory
$ mkdir public tmp
$ passenger start
person Serkan Durusoy    schedule 25.02.2014

Ответ Фатих-Арслан с Поправка Derwiwie сработала как шарм. Одна вещь, которую мне пришлось использовать, - это поместить wss вместо ws, потому что моя служба работает только в https.

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