WebSockets и прокси Apache: как настроить mod_proxy_wstunnel?


99

У меня есть :

  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?

Ответы:


161

Наконец-то мне это удалось, благодаря этой теме .

ДЕЛАТЬ:

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

3
Я все еще получаю 502 плохой шлюз для моих маршрутов ws: // при этом. Запуск Apache 2.4 на Ubuntu 14.04
Алекс Муро,

1
Это работает, потому что весь HTTP-трафик также пересылается, но если вы хотите перенаправить только трафик своего сокета, обратите внимание, что Socket.io начинает связь с HTTP-запросом на опрос. Больше информации здесь .
Эрик Купманс

4
Как переадресовать с 443 wss на ws? есть ли rewritecond изменения?
Эрнан Эче

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 Спасибо
Войтех Мраз

18

Может будет полезно. Просто все запросы отправляются через ws на узел

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

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

Спасибо @Sergey. Это помогло мне, когда я использовал только прямой путь, на который ссылается ws, вместо маршрутизации всего в корень документа. В ответе ниже я показал, что сделал, на благо других.
Anwaarullah

Этот ответ работает для простых веб-сокетов (без socket.io), поэтому для меня это лучший ответ
Томас

Потрясающие! Это сразу сработало для меня, в то время как другие попытки перезаписи и прокси не решили мою проблему.
Стефан

Спасибо!! Идеально подходит для базового варианта использования, просто веб-сокет с использованием ws: //
Антония Блэр

17

Начиная с 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
Не могли бы вы скопировать / вставить вместо скриншота? Заранее спасибо, это улучшит читаемость.
Basj 06

3

Сделал следующее для приложения Spring, запускающего статический контент, контент для отдыха и веб-сокет.

Apache используется в качестве прокси и конечной точки SSL для следующих URI:

  • / app → статический контент
  • / api → REST API
  • / api / ws → веб-сокет

Конфигурация 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где наш файл War, помещенный в tomcat, и tomcat обслуживает apache ws. Спасибо

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

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

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

Что такое Tomcat @ArvindMadhukar?
Basj

1

Для «опросного» транспорта.

Сторона Apache:

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