WebSockets та Apache проксі: як налаштувати mod_proxy_wstunnel?


98

У мене є :

  1. Apache(v2.4) на порту 80 мого сервера для www.domain1.com, з увімкненими mod_proxy та mod_proxy_wstunnel

  2. node.js + socket.io на порту 3001 того самого сервера.

Доступ www.domain2.com(з портом 80) переспрямовує на 2. завдяки описаному тут методу . Я встановив це в конфігурації Apache:

<VirtualHost *:80>
    ServerName www.domain2.com
    ProxyPass / http://localhost:3001/
    ProxyPassReverse / http://localhost:3001/
    ProxyPass / ws://localhost:3001/
    ProxyPassReverse / ws://localhost:3001/
</VirtualHost>

Він працює для всього, крім частини веб-розетки: ws://...проксі-сервер не передає його, як слід.

Коли я заходжу на сторінку www.domain2.com, у мене є:

Impossible to connect ws://www.domain2.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.

Питання: Як зробити Apache також проксі-сервером WebSockets?

Відповіді:


160

Нарешті мені вдалося це зробити, завдяки цій темі .

РОБИТИ:

1) Установіть Apache 2.4 (не працює з 2.2) та виконайте:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) nodejsЗапустити порт 3001

3) Зробіть це в конфігурації Apache

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
  RewriteCond %{QUERY_STRING} transport=websocket    [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]

  ProxyPass / http://localhost:3001/
  ProxyPassReverse / http://localhost:3001/
</VirtualHost>

Примітка: якщо у вас на одному сервері більше одного сервісу, який використовує веб-сокети, можливо, ви захочете зробити це, щоб розділити їх.


FWIW, Apache 2.4 у CentOS 7.1 має цю помилку, тому перезапис не розпізнає протокол ws: // і додає домен перед відправленням підзапиту. Ви можете випробувати себе, змінивши прапор [P] roxy на [R] edirect.
Андор,

3
Я все ще отримую 502 поганий шлюз для моїх маршрутів ws: //, роблячи це. Запуск Apache 2.4 на Ubuntu 14.04
Alex Muro

1
Це працює, оскільки весь HTTP-трафік також переадресовується, але якщо ви хочете переадресувати лише ваш сокет-трафік, зверніть увагу, що Socket.io починає зв'язок із запитом на опитування HTTP. Більше інформації тут .
Ерік Купманс,

4
Як переадресувати з 443 wss на ws? переписує другі зміни?
Hernán Eche

1
Стан RewriteCond %{QUERY_STRING} transport=websocket [NC]не працює правильно мене. Пропоную використовувати RewriteCond %{HTTP:Upgrade} =websocket [NC]замість цього.
Мартін

99

Замість фільтрування за URL-адресою можна також фільтрувати за заголовком HTTP. Ця конфігурація буде працювати для будь-яких веб-додатків, які використовують веб-сокети, також якщо вони не використовують socket.io:

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*)           http://localhost:3001/$1 [P,L]

  ProxyPassReverse / http://localhost:3001/
</VirtualHost>

Це добре працює для мене, але я проксіюю підпуть, і я виявив, що важливо додати прив'язки ^, оскільки регулярний вираз шукає підрядок. Наприклад, RewriteRule ^ [^ /] * / foo /(.*) http: // $ {FOO_HOST} / $ 1 [P, L] (інакше / bar / foo також буде спрямовано туди ж, де / foo)
Стів Lilly

Ця конфігурація найкраще працює на хмарі alibaba. Крім того, це виправить помилку net :: ERR_RESPONSE_HEADERS_TRUNCATED "Сподіваюся, хтось вважає це корисним.
Майк Мусні

Використовуючи SignalR, я можу сказати, це найкраще мені вдалося +1 Дякую
Vojtěch Mráz

18

Можливо, буде корисним. Просто всі запити надсилаються через ws на вузол

<VirtualHost *:80>
  ServerName www.domain2.com

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>

Дякую @Sergey. Це допомогло мені, коли я використовував лише прямий шлях, на який посилається ws, замість того, щоб маршрутизувати все до кореневого документа. Я показав, що зробив у відповіді нижче на користь інших.
Anwaarullah

Ця відповідь працює для простих веб-сокетів (без socket.io), тому для мене це краща відповідь
Томас

Дивовижно! Це моментально працювало для мене, тоді як інші спроби перезапису та проксі не вирішили моєї проблеми.
Стефан

Дякую!! Ідеально підходить для базового використання, просто простий веб-сокет із використанням ws: //
Антонія Блер

16

Станом на Socket.IO 1.0 (травень 2014 р.) Усі підключення починаються із запиту на опитування HTTP (докладніше тут ). Це означає, що крім переадресації трафіку WebSocket, вам потрібно переслати будь-які transport=pollingHTTP-запити.

Рішення нижче має перенаправляти весь трафік сокетів правильно, не перенаправляючи будь-який інший трафік.

  1. Увімкніть такі моди Apache2:

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
  2. Використовуйте ці налаштування у файлі * .conf (наприклад /etc/apache2/sites-available/mysite.com.conf). Я включив коментарі, щоб пояснити кожен фрагмент:

    <VirtualHost *:80>
        ServerName www.mydomain.com
    
        # Enable the rewrite engine
        # Requires: sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
        # In the rules/conds, [NC] means case-insensitve, [P] means proxy
        RewriteEngine On
    
        # socket.io 1.0+ starts all connections with an HTTP polling request
        RewriteCond %{QUERY_STRING} transport=polling       [NC]
        RewriteRule /(.*)           http://localhost:3001/$1 [P]
    
        # When socket.io wants to initiate a WebSocket connection, it sends an
        # "upgrade: websocket" request that should be transferred to ws://
        RewriteCond %{HTTP:Upgrade} websocket               [NC]
        RewriteRule /(.*)           ws://localhost:3001/$1  [P]
    
        # OPTIONAL: Route all HTTP traffic at /node to port 3001
        ProxyRequests Off
        ProxyPass           /node   http://localhost:3001
        ProxyPassReverse    /node   http://localhost:3001
    </VirtualHost>
  3. Я включив додатковий розділ для маршрутизації /nodeтрафіку, який мені здається зручним, див. Тут для отримання додаткової інформації.


1
Для мене це чудово працює. Зверніть увагу, що якщо ваші запити надходять на URL-адресу, відмінну від кореневої, ви можете це зробити, наприкладRewriteRule /path/(.*)
Роб Гвін-Джонс

8

За допомогою цих відповідей я нарешті отримав зворотний проксі-сервер для Node-RED, що працює на Raspberry Pi з Ubuntu Mate та Apache2, що працюють, використовуючи цю конфігурацію сайту Apache2:

<VirtualHost *:80>
    ServerName nodered.domain.com
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://localhost:1880/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://localhost:1880/$1 [P,L]
</VirtualHost>

Мені також довелося ввімкнути такі модулі:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel

7

Для мене це працює після додавання лише одного рядка в httpd.conf, як показано нижче (жирний рядок).


<VirtualHost *:80>
    ServerName: xxxxx

    #ProxyPassReverse is not needed
    ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>

Версія Apache - 2.4.6 на CentOS.


5

Моє налаштування:

  • Apache 2.4.10 (працює на Debian)
  • Node.js (версія 4.1.1) Додаток, що працює на порту 3000, що приймає WebSockets на шляху /api/ws

Як згадано вище @Basj, переконайтеся, що проксі-сервер a2enmod та ws_tunnel увімкнені.

Це знімок екрана файлу конфігурації Apache, який вирішив мою проблему:

Конфігурація Apache

Відповідна частина у вигляді тексту:

<VirtualHost *:80>
  ServerName *******
  ServerAlias *******
  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/

  <Location "/api/ws">
      ProxyPass "ws://localhost:3000/api/ws"
  </Location>
</VirtualHost>

Сподіваюся, що це допомагає.


У мене виникають проблеми з налаштуванням мого додатка з бажаною URL-адресою, а не за замовчуванням. Не могли б ви допомогти мені? (Я сиджу над сервером кеш-пам’яті лаків)
Джош

6
Не могли б ви скопіювати / вставити замість знімка екрана? Дякую заздалегідь, це покращить читабельність.
Бас

3

Зробив наступне для весняної програми, що запускає статичний вміст, вміст відпочинку та веб-розетки.

Apache використовується як проксі-сервер та кінцева точка SSL для таких URI:

  • / app → статичний вміст
  • / api → REST API
  • / api / ws → websocket

Налаштування Apache

<VirtualHost *:80>
    ServerName xxx.xxx.xxx    

    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    <Proxy *>
         Require all granted
    </Proxy>

    RewriteEngine On

    # websocket 
    RewriteCond %{HTTP:Upgrade}         =websocket                      [NC]
    RewriteRule ^/api/ws/(.*)           ws://localhost:8080/api/ws/$1   [P,L]

    # rest
    ProxyPass /api http://localhost:8080/api
    ProxyPassReverse /api http://localhost:8080/api

    # static content    
    ProxyPass /app http://localhost:8080/app
    ProxyPassReverse /app http://localhost:8080/app 
</VirtualHost>

Я використовую ту саму конфігурацію vHost для конфігурації SSL, не потрібно нічого змінювати, пов’язану з проксі.

Пружинна конфігурація

server.use-forward-headers: true

Використовуйте тег Location для відокремлення місцеположень, тобто: <Location / app> ProxyPass localhost: 8080 / app ProxyPassReverse localhost: 8080 / app </Location>
CrazyMerlin

2

Користуйтеся цим посиланням для перфактного рішення для ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

Ви просто повинні зробити нижче крок ..

Йти до /etc/apache2/mods-available

Крок 1

Увімкніть mode proxy_wstunnel.load, використовуючи команду нижче

$a2enmod proxy_wstunnel.load

Крок ... 2

Йти до /etc/apache2/sites-available

і додайте нижній рядок у файл .conf у віртуальному хості

ProxyPass "/ws2/"  "ws://localhost:8080/"

ProxyPass "/wss2/" "wss://localhost:8080/"

Примітка: 8080 означає, що ваш порт, що працює на tomcat, тому що ми хочемо підключитися, wsде наш файл війни, розміщений у tomcat і tomcat, служить для apache ws. спасибі

Моя конфігурація

ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected

Вибачте, я насправді не розумію (особливо ваше останнє речення). Чи можете ви покращити форматування відповіді та додати деталі для людей, які не знають всього, що ви згадали?
Basj

Що таке Tomcat @ArvindMadhukar?
Basj

1

Для "виборчого" транспорту.

Сторона апача:

<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /my/path


    ProxyRequests Off

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
    ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io   
</VirtualHost>

Сторона клієнта:

var my_socket = new io.Manager(null, {
    host: 'mysite.com',
    path: '/my-connect-3001'
    transports: ['polling'],
}).socket('/');

1

На додаток до основної відповіді: якщо у вас є більше однієї служби на одному сервері, який використовує веб-сокети, ви можете зробити це, щоб розділити їх, використовуючи спеціальний шлях (*):

Сервер вузлів:

var io = require('socket.io')({ path: '/ws_website1'}).listen(server);

Клієнтський HTML:

<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...

Конфігурація Apache:

RewriteEngine On

RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]

(*) Примітка: використання за замовчуванням RewriteCond %{REQUEST_URI} ^/socket.ioне буде характерним для веб-сайту, а запити веб-сокетів будуть змішані між різними веб-сайтами!


0

РОБИТИ:

  1. Встановіть Apache 2.4 (не працює з 2.2) a2enmod proxyтаa2enmod proxy_wstunnel.load

  2. Зробіть це в конфігурації Apache,
    просто додайте два рядки у файл, де 8080 є вашим запущеним портом tomcat

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.