mod_proxy_wstunnel apache ssl websocket mod-proxy

mod_proxy_wstunnel - apache websocket virtualhost



tunelizaciĆ³n de conexiones websocket seguras con apache (3)

Tengo una ejecución de Apache que solo es accesible a través de HTTPS. Quiero servir websockets desde una aplicación de servidor adicional que se ejecuta en la misma máquina, pero dado que no es posible que los clientes se conecten en otro puerto que no sea el 443 a nuestro servidor, esas conexiones websocket se deben enviar mediante proxy a través del Apache.

Ahora, instalé mod_proxy y lo configuré de la siguiente manera:

SSLProxyEngine on ProxyPass /ws https://127.0.0.1:9001

Esto no funciona sin embargo. Ahora puedo conectarme a https: // server / ws en mi navegador, pero parece que apache se traga parte de los encabezados de websockets, por lo que las conexiones reales de websocket no funcionan.

¿Cómo puedo realizar un túnel de mis conexiones de websocket a través del servidor Apache?



Lo tengo funcionando.

Guión

------------- ---------------- ---------- | Browser |<----->| Apache httpd |<----->| Tomcat | | | SSL | 2.4.9 | SSL | 7.0.52 | ------------- ---------------- ----------

Navegador WebSocket a través de Apache httpd, proxy inverso a la aplicación web en Tomcat. Todos los SSL front-to-back.

Aquí está la configuración para cada pieza:

Cliente del navegador

Tenga en cuenta la "/" final en la url: wss://host/app/ws/ . Fue necesario hacer coincidir la directiva wss ProxyPass correcta (que se muestra más adelante en la sección de configuración de Apache) y evitar un redireccionamiento 301 a https://host/app/ws . Es decir, se estaba redirigiendo utilizando el esquema https y no el esquema wss para el back-end.

Página de prueba

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

Estoy usando Apache httpd 2.4.9, que de manera inmediata proporciona mod_proxy_wstunnel . Sin embargo, el mod_proxy_wstunnel.so proporcionado no es compatible con SSL cuando se usa el esquema wss: //. Termina intentando conectarse al back-end (Tomcat) en texto plano, lo que falla el protocolo de enlace SSL. Ver error here . Por lo tanto, debe parchear mod_proxy_wstunnel.c usted mismo siguiendo la corrección sugerida en el informe de error. Es un cambio fácil de 3 líneas.

Suggested correction, 314a315 > int is_ssl = 0; 320a322 > is_ssl = 1; 344c346 < backend->is_ssl = 0; --- > backend->is_ssl = is_ssl;

Luego reconstruya el módulo y reemplace en su nuevo mod_proxy_wstunnel.so con el anterior.

Construyendo Apache httpd

Aquí está el comando (2.4.9) que utilicé para construir los módulos que quería. Puede que no los necesites a todos.

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

Tenga en cuenta el último cambio: --enable-proxy_wstunnel=shared Al principio, estaba usando incorrectamente --enable-proxy-wstunnel=shared , que parecía funcionar bien, pero al final no funcionaba cuando usaba el archivo resultante .so . ¿Ver la diferencia? Desea asegurarse de utilizar un guión bajo en "proxy_wstunnel" lugar de un guión.

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/

Si no viste mi nota en la configuración anterior, aquí está otra vez: ¡ Presta atención estricta a las barras diagonales "/" o la falta de ellas!

Además, si está viendo las declaraciones del registro de depuración en su registro de apache que dice que se realizó una conexión wss y luego se cerró, es posible que tenga mod_reqtimeout habilitado como lo hice, así que asegúrese de que no esté cargado:

#LoadModule reqtimeout_module modules/mod_reqtimeout.so

Gato

Suponiendo que su conector HTTP esté configurado correctamente, no hay mucho que configurar en Tomcat. Aunque para ayudar en la depuración, me pareció útil crear un $CATALINA_HOME/bin/setenv.sh que tenía este aspecto:

setenv.sh

CATALINA_OPTS=$CATALINA_OPTS" -Djavax.net.debug=all -Djavax.net.debug=ssl:handshake:verbose"

Esto me permitió ver si el mod_proxy_wstunnel.so que modifiqué funcionaba o no para wss: //. Cuando no funcionaba, mi archivo de registro catalina.out mostraba:

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()

Pensamientos finales

Aunque estoy usando Apache httpd 2.4.9, he visto dónde se pueden aplicar los backports de mod_proxy_wstunnel a las versiones 2.2.x. Espero que mis notas anteriores se puedan aplicar a esas versiones anteriores.


Si no desea que Apache finalice la conexión SSL (y envíe tráfico WebSocket no cifrado), pero que el SSL finalice en el servidor WebSocket de destino final y desee exclusivamente utilizar WSS en el tráfico WebSocket que ingresa a Apache, entonces mod_proxy_connect puede ser capaz sólo para conectarse a través del tráfico en bruto. No es seguro. También me interesaría si eso funciona.

Si lo anterior no se cumple, aquí hay más información:

En cualquier caso, el uso de Apache limitará severamente la escalabilidad con respecto al número de conexiones de WebSocket servidas simultáneamente, ya que cada conexión WS consumirá 1 proceso / subproceso en Apache.