Я использую Apache 2.4.7 в качестве обратного прокси на Ubuntu 14.04 LTS. Этот сервер Apache действует как точка входа для множества различных серверных приложений, доступ к которым осуществляется через различные конфигурации mod_proxy в <Location>
блоки
Мне нужно предоставить обратный прокси-доступ к приложению, которое использует WebSockets. Это приложение Java Spring, которое обслуживает HTML и другие статические файлы через HTTP, а затем использует WebSocket для динамических данных после загрузки страницы.
У меня запущено приложение Nginx
используя следующую конфигурацию:
location /newapp/ {
proxy_pass http://newapp.example.com:8080/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
К сожалению, из-за того, что мне нужен модуль аутентификации Apache, которого нет на Nginx, я не могу использовать его в производственной среде.
Что я хочу сделать в псевдо-Apache-config:
<Location /newapp/>
if not WebSockets:
ProxyPass http://newapp.example.com:8080/
ProxyPassReverse /
else
ProxyPass ws://newapp.example.com:8080/
ProxyPassReverse /
</Location>
Апач mod_proxy_wstunnel
модуль заставляет меня думать, что это должно быть возможно. Доступ к WebSocket осуществляется по URL-адресу /api/socket/...
, поэтому я попытался разделить два типа ProxyPass
используя отдельные <Location>
блоки:
<Location /newapp/>
ProxyPass http://newapp.example.com:8080/ disablereuse=on
ProxyPassReverse /
ProxyPassReverseCookieDomain newapp.example.com apps.example.com
ProxyPassReverseCookiePath http://newapp.example.com:8080/ /newapp/
</Location>
<Location /newapp/api/socket/>
ProxyPass ws://newapp.example.com:8080/api/socket/
ProxyPassReverse /
</Location>
Изначально это работает - браузер запрашивает http://apps.example.com/newapp/страница загружается по HTTP, статические ресурсы загружаются, код JavaScript подключается к веб-сокету, все в порядке.
Однако, когда новый запрос делается через HTTP - скажем, для GET /newapp/static/someimage.png
, что-то идет не так. Этот запрос не соответствует местоположению WebSocket, поэтому я ожидаю, что он будет прокси GET /static/someimage.png
сквозь http://newapp.example.com:8080/
.
Вместо этого сервер приложений получает запрос на GET /newapp/static/someimage.png
и возвращает 404, поскольку это не тот URL, о котором он знает. Это нарушает работу приложения, так как HTTP-запросы, которые должны работать, не работают.
Ноты:
GET /newapp/api/ajax/someapicall
также неправильно проксируется.<Location /newapp/api/socket/>
Раздел вызывает две вещи: WebSocket не может подключиться и HTTP-запросы продолжают работать.Я думаю, что происходит:
думаю mod_proxy_wstunnel
, после активации первым запросом на соответствие /newapp/api/socket/
, принимает на себя все последующие входящие запросы от клиента, независимо от того, соответствуют ли они Location
или не. Я проверил это, добавив RequestHeader set Test "some_identifying_value"
директива каждому Location
- HTTP-запросы для статических файлов и для /api/socket/info
имел Test
заголовок на них, но неправильно проксированные HTTP-запросы не имели Test
заголовок на них, что говорит о том, что они передаются напрямую, не обрабатываются директивами Apache.
В конечном счете, мой вопрос таков: можно ли настроить любую версию Apache (я счастлив обновить!) Для приложений на основе WebSocket с обратным прокси-сервером таким образом, чтобы HTTP-запросы также правильно выполнялись обратным проксированием после того, как WebSocket связано? Если да, то как это настроено?
Ответ Андерса помог мне добраться туда на 95%.
Базовый сценарий:
newapp.example.com
/api/socket/
http://apps.example.com/newapp/
Вот как настроить WebSockets и обратное проксирование HTTP для описанного выше сценария в <Location>
блок:
<Location /newapp/>
ProxyPass http://newapp.example.com:8080/
ProxyPassReverse /
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule /api/(.*) ws://newapp.example.com:8080/api/$1 [P]
</Location>
Последнее правило перезаписи имеет решающее значение - без него мы передадим запрос /newapp/api/socket
через сервер WebSocket, который он отклонит.
Регулярное выражение разбирает все после api
- может быть лучший способ захватить этот блок, но это сработало. Затем мы должны не забыть повторно добавить /api/
на конечный URL перенаправления.
Самое главное, HTTP-запросы продолжают работать после установления соединения WebSocket!
Я использую apache 2.4 в качестве прокси перед моим весенним загрузочным приложением, это приложение обслуживает некоторые остальные вызовы api, веб-сокеты (sockjs) и некоторые статические страницы. У меня были проблемы с работой веб-сокета, секрет заключался в том, чтобы добавить правила перезаписи вы видите ниже, теперь это работает для меня, моя конфигурация виртуального хоста apache выглядит так:
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/httpd/ssl/my.crt
SSLCertificateKeyFile /etc/httpd/ssl/my.key
SSLCertificateChainFile /etc/httpd/ssl/intermediate.crt
ProxyPreserveHost On
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
ProxyRequests Off
RewriteEngine on
RewriteCond %{HTTP:UPGRADE} ^WebSocket$ [NC]
RewriteCond %{HTTP:CONNECTION} Upgrade$ [NC]
RewriteRule .* ws://localhost:6868%{REQUEST_URI} [P]
ServerName my.dnsname.com
</VirtualHost>