Utiliser socket.io (et les websockets) avec Apache

Je vois déjà certains venir et dire qu’Apache pas fait pour ça, que son rôle est d’afficher des pages statiques ou PHP brute et que tout le reste devrait être laissé à un vrai serveur proxy ou à un serveur web plus récent comme Nginx. Alors oui … Mais quand on n’a pas envie de s’embêter à mettre en place un système compliqué et juste monter un node à l’arrache pour faire une tâche précise, Apache est largement suffisant.

Malheureusement, le support du websocket dans le mod_proxy d’Apache n’est assuré qu’à partir de la version 2.4. Or, la version proposée actuellement dans les dépôts Debian (ou autre Linux stable) est généralement la 2.2. Faut t-il pour autant basculer sur une branche de mise à jour instable ?

Je vous propose aujourd’hui de compiler vous-même l’extension mod_proxy_wstunnel qui permettra de vous servir de websocket sans trop de problèmes.

1) Récupération des sources

Cette étape va différer en fonction de votre distribution Linux.

Si vous êtes sur Debian comme moi, vous pouvez utiliser apt et ceci suiffera :
apt-get source apache2

La méthode qui fonctionnera sur tous les Linux sera de récupérer les sources sur le SVN d’Apache. Veuillez prendre attention à bien récupérer la version de votre Apache :
svn checkout http://svn.apache.org/repos/asf/httpd/httpd/tags/2.2.22/ apache2-2.2.22

2) Application du patch

Nous avons les sources de la version actuelle, mais pas les modifications requises pour obtenir le module de la version 2.4. Que cela ne tienne, Mr Bernard Cafarelli, ingénieur français passionné par le système Gentoo, a backporté (transposé le code d’une version ultérieure à une version antérieure) le code pour qu’il fonctionne sur les anciennes versions d’Apache.

Déplacez vous dans le dossier de sources, récupérez et appliquez son fichier patch :
cd apache2-2.2.22
wget http://cafarelli.fr/gentoo/apache-2.2.24-wstunnel.patch
patch -p1 < apache-2.2.24-wstunnel.patch

Si vous voyez ceci, c’est que le patch c’est bien appliqué :
patching file modules/proxy/config.m4
patching file modules/proxy/mod_proxy.h
Hunk #1 succeeded at 769 (offset -1 lines).
patching file modules/proxy/mod_proxy_wstunnel.c
patching file modules/proxy/mod_proxy_wstunnel.dsp
patching file modules/proxy/NWGNUmakefile
patching file modules/proxy/NWGNUproxywstunnel
patching file modules/proxy/proxy_util.c
Hunk #1 succeeded at 2678 (offset -2 lines).

3) Re-compilation

Uniquement si vous êtes sur un système Debian (et que vous avez récupéré les sources via apt-get), tapez ceci :
./buildconf

Ensuite, tapez les commandes habituelles (en oubliant pas le petit switch supplémentaire). N’oubliez pas d’avoir installé les outils nécessaires à une compilation avant (packet build-essential sous Debian)
./configure --enable-proxy=shared --enable-proxy_wstunnel=shared
make

4) Sauvegarde et copie des fichiers générés

Dans ce qui a été généré, nous allons ne copier que deux fichiers : mod_proxy.so et mod_proxy_wstunnel.so.

Le fichier mod_proxy.so est un fichier déjà présent et utilisé par Apache, nous allons en garder une copie au cas où la manipulation tourne mal :
sudo cp /usr/lib/apache2/modules/mod_proxy.so /usr/lib/apache2/modules/mod_proxy.so.bak

Copions ensuite les deux fichiers dans les libs d’Apache :
sudo cp modules/proxy/.libs/mod_proxy.so /usr/lib/apache2/modules/
sudo cp modules/proxy/.libs/mod_proxy_wstunnel.so /usr/lib/apache2/modules/

5) Charger le nouveau module

Il nous faut créer ensuite le fichier de chargement du module. Pour cela, créez un nouveau fichier ici :
/etc/apache2/mods-available/proxy_wstunnel.load
Et mettez-y ceci :
# Depends: proxy
LoadModule proxy_wstunnel_module /usr/lib/apache2/modules/mod_proxy_wstunnel.so

Il ne vous reste plus qu’à activer l’extension et redémarrer Apache tel qu’il vous l’a demandé :
sudo a2enmod proxy_wstunnel
sudo service apache2 restart

6) Régler le virtualhost

Pour créer le proxy websocket, il nous suffit d’ajouter ceci dans un de vos virtualhost :
ProxyPass / ws://127.0.0.1:8888/
ProxyPassReverse / ws://127.0.0.1:8888/

Bien sûr, remplacez le port et le chemin par les vôtres 😉

Petit inconvénient de cette technique, un reload ne suffit pas pour activer ou modifier une configuration de proxy : un redémarrage d’Apache est nécessaire.

Actuellement, vos websockets fonctionneront … Hormis socket.io. En effet, celui-ci est un peu chiant, car son process charge une partie des données en HTTP et l’autre en websocket … Le tout sur le même port et en utilisant le même chemin :-/

Pas de panique, il y a un moyen simple de contrer ceci. Notez que j’ai choisi dans mon virtualhost d’héberger ça sur un sous domaine, il n’y a pas de raison que cela ne fonctionne pas sur son domaine principal, à condition qu’il n’y ait rien qui tape sur l’adresse /socket.io/
<VirtualHost *:80 *:443>
ServerName node.bidule.fr
RewriteEngine On
RewriteRule /socket.io/1/websocket/ - [R=200,L]
ProxyPass /socket.io/socket.io.js http://127.0.0.1:8888/socket.io/socket.io.js
ProxyPassReverse /socket.io/socket.io.js http://127.0.0.1:8888/socket.io/socket.io.js
ProxyPass /socket.io/1/websocket ws://127.0.0.1:8888/socket.io/1/websocket
ProxyPassReverse /socket.io/1/websocket ws://127.0.0.1:8888/socket.io/1/websocket
ProxyPass /socket.io/1/ http://127.0.0.1:8888/socket.io/1/
ProxyPassReverse /socket.io/1/ http://127.0.0.1:8888/socket.io/1/
</VirtualHost>

Comme vous le voyez, j’ai entièrement refait le process de connexion à socket.io … mais à l’envers. N’hésitez pas à rajouter la ligne de l’étape 6 si votre node écoute aussi l’HTTP à la racine 😉

C’est tout pour aujourd’hui, faites bien joujou et n’abusez pas trop des WS 😀

Une réflexion au sujet de « Utiliser socket.io (et les websockets) avec Apache »

  1. Merci beaucoup ça m’a bien aidé!
    Juste pour la conf du vhost, elle ne marche pas avec la nouvelle version de socket.io (1.0).
    Du coup, en voici une qui marche (debian6 + apache2.2.16 + backport mod_proxy_wstunnel + socket.io1.0):

    RewriteEngine on

    RewriteCond %{QUERY_STRING} transport=polling
    RewriteRule /(.*)$ http://localhost:4567/$1 [P]

    ProxyRequests off
    ProxyPass /socket.io/ ws://localhost:4567/socket.io/
    ProxyPassReverse /socket.io/ ws://localhost:4567/socket.io/

    ProxyPass / http://localhost:4567/
    ProxyPassReverse / http://localhost:4567/

    En remplaçant l’host et le port par le votre.

Laisser un commentaire