tunneling des connexions sécurisées websocket avec apache

J’ai un Apache qui est accessible uniquement via HTTPS. Je veux servir des websockets à partir d’une application serveur supplémentaire qui s’exécute sur le même ordinateur, mais comme les clients ne peuvent pas se connecter sur un autre port que 443 à notre serveur, ces connexions doivent être transmises via Apache.

Maintenant, j’ai installé mod_proxy et l’ai configuré comme suit:

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

Cela ne fonctionne pas cependant. Je peux maintenant me connecter à https: // server / ws dans mon navigateur, mais Apache semble avaler une partie des en-têtes de websockets, de sorte que les connexions réelles aux websocket ne fonctionnent pas.

Comment puis-je effectuer le tunneling de mes connexions websocket via le serveur Apache?

Je l’ai fait fonctionner.

Scénario

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

Navigateur WebSocket via Apache httpd, inverser le proxy vers l’application Web dans Tomcat. Tout SSL avant-arrière.

Voici la configuration de chaque pièce:

Navigateur Client

Notez le “/” wss://host/app/ws/ dans l’url: wss://host/app/ws/ . Il était nécessaire de faire correspondre la directive wss ProxyPass correcte (indiquée plus bas dans la section de configuration d’Apache) et d’empêcher une redirection 301 vers https://host/app/ws . En d’autres termes, il était redirigé en utilisant le schéma https et non le schéma wss pour le back-end.

Page de test

      

Apache httpd

J’utilise Apache httpd 2.4.9, qui fournit par défaut mod_proxy_wstunnel . Cependant, le fichier mod_proxy_wstunnel.so fourni ne prend pas en charge le protocole SSL lors de l’utilisation du schéma wss: //. Il finit par essayer de se connecter au back-end (Tomcat) en texte brut, ce qui échoue à la négociation SSL. Voir bug ici . Donc, vous devez patcher mod_proxy_wstunnel.c en suivant la correction suggérée dans le rapport de bogue. C’est un changement facile à 3 lignes.

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

Recréez ensuite le module et remplacez-le dans votre nouveau mod_proxy_wstunnel.so avec l’ancien.

Construire Apache httpd

Voici la commande (2.4.9) que j’ai utilisée pour construire les modules que je voulais. Vous n’avez peut-être pas besoin d’eux tous.

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

Notez le dernier changement: --enable-proxy_wstunnel=shared Au début, je n’utilisais pas correctement --enable-proxy-wstunnel=shared , ce qui semblait bien se --enable-proxy-wstunnel=shared , mais ne fonctionnerait finalement pas lorsque j’utilisais le fichier .so résultant . Regarde la différence? Vous voulez vous assurer d’utiliser un trait de soulignement dans "proxy_wstunnel" plutôt qu’un tiret.

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! # # ProxyPass wss://localhost:8443/app/ws # ProxyPassReverse wss://localhost:8443/app/ws # # # ProxyPass https://localhost:8443/app/ # ProxyPassReverse https://localhost:8443/app/ # # NOTE: Pay ssortingct 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 vous n’avez pas vu ma note dans la configuration ci-dessus, la voici encore: Faites très attention aux barres obliques “/” ou à leur absence!

De plus, si vous voyez des instructions de journal de débogage dans votre journal Apache indiquant qu’une connexion wss a été établie puis fermée, il est possible que mod_reqtimeout soit activé, alors assurez-vous qu’il n’est pas chargé:

 #LoadModule reqtimeout_module modules/mod_reqtimeout.so 

Matou

En supposant que votre connecteur HTTP est configuré correctement, il n’ya pas grand chose à configurer dans Tomcat. Bien que pour faciliter le débogage, j’ai trouvé utile de créer un $CATALINA_HOME/bin/setenv.sh qui ressemblait à ceci:

setenv.sh

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

Cela m’a permis de voir si le mod_proxy_wstunnel.so que j’avais modifié fonctionnait ou pas pour wss: //. Lorsque cela ne fonctionnait pas, mon fichier journal catalina.out afficherait:

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

Dernières pensées

Bien que j’utilise Apache httpd 2.4.9, j’ai vu où les backports de mod_proxy_wstunnel peuvent être appliqués aux versions 2.2.x. J’espère que mes notes ci-dessus peuvent être appliquées à ces anciennes versions.

Si vous ne souhaitez pas qu’Apache termine la connexion SSL (et transfère le trafic WebSocket non chiffré), mais que le protocole SSL se termine sur le serveur WebSocket cible final et que vous souhaitiez uniquement utiliser WSS sur le trafic WebSocket entrant dans Apache, alors mod_proxy_connect peut juste se connecter via le trafic brut. Pas certain. Je serais également intéressé si cela fonctionne.

Si ci-dessus ne tient pas, voici plus d’informations:

Dans tous les cas, l’utilisation d’Apache limitera considérablement l’évolutivité en ce qui concerne le nombre de connexions WebSocket servies simultanément, car chaque connexion WS consumra 1 processus / thread sur Apache.

J’essaie d’installer ce https://github.com/kawasima/mod_proxy_websocket . J’espère que cela aide.