Ответ 1
У меня это работает.
Сценарий
------------- ---------------- ----------
| Browser |<----->| Apache httpd |<----->| Tomcat |
| | SSL | 2.4.9 | SSL | 7.0.52 |
------------- ---------------- ----------
Браузер WebSocket через Apache httpd, обратный прокси к веб-приложению в Tomcat. Все SSL-обратные.
Здесь конфигурация для каждой части:
Клиент браузера
Обратите внимание на конечный "/" в URL: wss://host/app/ws/
. Необходимо было подобрать правильную директиву wss ProxyPass (показанную далее в разделе конфигурации Apache) и предотвратить перенаправление 301 на https://host/app/ws
. То есть он перенаправлялся с использованием схемы https, а не для схемы wss для back-end.
<!doctype html>
<body>
<script type="text/javascript">
var connection = new WebSocket("wss://host/app/ws/");
connection.onopen = function () {
console.log("connected");
};
connection.onclose = function () {
console.log("onclose");
};
connection.onerror = function (error) {
console.log(error);
};
</script>
</body>
</html>
Apache httpd
Я использую Apache httpd 2.4.9, который из коробки предоставляет mod_proxy_wstunnel. Однако предоставленный mod_proxy_wstunnel.so не поддерживает SSL при использовании схемы wss://. В результате он пытается подключиться к фоновому контенту (Tomcat) в обычном тексте, что не позволяет SSL-квитирование. Смотрите здесь здесь. Итак, вы должны исправить mod_proxy_wstunnel.c самостоятельно, выполнив предложенную коррекцию в отчете об ошибке. Это легкое 3-х строчное изменение.
Suggested correction,
314a315
> int is_ssl = 0;
320a322
> is_ssl = 1;
344c346
< backend->is_ssl = 0;
---
> backend->is_ssl = is_ssl;
Затем перестройте модуль и замените его в новом mod_proxy_wstunnel.so старым.
Построение Apache httpd
Здесь (2.4.9) команда, которую я использовал для сборки модулей, которые я хотел. Возможно, вам не нужны все.
./configure --prefix=/usr/local/apache --with-included-apr --enable-alias=shared
--enable-authz_host=shared --enable-authz_user=shared
--enable-deflate=shared --enable-negotiation=shared
--enable-proxy=shared --enable-ssl=shared --enable-reqtimeout=shared
--enable-status=shared --enable-auth_basic=shared
--enable-dir=shared --enable-authn_file=shared
--enable-autoindex=shared --enable-env=shared --enable-php5=shared
--enable-authz_default=shared --enable-cgi=shared
--enable-setenvif=shared --enable-authz_groupfile=shared
--enable-mime=shared --enable-proxy_http=shared
--enable-proxy_wstunnel=shared
Обратите внимание на самый последний переключатель: --enable-proxy_wstunnel=shared
. Сначала я неправильно использовал --enable-proxy-wstunnel=shared
, который, казалось, строился отлично, но в конечном счете не работал, если Я использовал полученный .so файл. Увидеть разницу? Вы хотите удостовериться, что используйте знак подчеркивания "proxy_wstunnel"
, а не тире.
Apache httpd config
httpd.conf...
LoadModule proxy_module modules/mod_proxy.so
...
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
...
LoadModule ssl_module modules/mod_ssl.so
...
Include conf/extra/httpd-ssl.conf
...
LogLevel debug
ProxyRequests off
# Note, this is the preferred ProxyPass configuration, and *should* be equivalent
# to the same inline version below, but it does NOT WORK!
#<Location /app/ws/>
# ProxyPass wss://localhost:8443/app/ws
# ProxyPassReverse wss://localhost:8443/app/ws
#</Location>
#<Location /app/>
# ProxyPass https://localhost:8443/app/
# ProxyPassReverse https://localhost:8443/app/
#</Location>
# NOTE: Pay strict attention to the slashes "/" or lack thereof!
# WebSocket url endpoint
ProxyPass /app/ws/ wss://localhost:8443/app/ws
ProxyPassReverse /app/ws/ wss://localhost:8443/app/ws
# Everything else
ProxyPass /app/ https://localhost:8443/app/
ProxyPassReverse /app/ https://localhost:8443/app/
Если вы не заметили мою заметку в приведенной выше конфигурации, здесь она снова: Уделите пристальное внимание косам "/" или их отсутствию!
Кроме того, если вы видите инструкции журнала отладки в своем журнале apache, в котором говорится, что соединение wss было завершено, тогда вы можете отключить mod_reqtimeout, как и я, поэтому убедитесь, что он не загружен:
#LoadModule reqtimeout_module modules/mod_reqtimeout.so
Tomcat
Предполагая, что ваш HTTP-коннектор настроен правильно, в tomcat не так много настроек. Хотя для помощи в отладке мне было полезно создать $CATALINA_HOME/bin/setenv.sh
, который выглядит так:
CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"
Это позволило мне увидеть, работает ли mod_proxy_wstunnel.so, который я модифицировал, или нет для wss://. Когда он не работал, файл журнала catalina.out будет показывать:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
http-nio-8443-exec-1, SEND TLSv1 ALERT: fatal, description = internal_error
http-nio-8443-exec-1, WRITE: TLSv1 Alert, length = 2
http-nio-8443-exec-1, called closeOutbound()
http-nio-8443-exec-1, closeOutboundInternal()
Заключительные мысли
Хотя я использую Apache httpd 2.4.9, Я видел, где backports mod_proxy_wstunnel можно применить к версиям 2.2.x. Надеюсь, мои заметки выше могут быть применены к тем более старым версиям.