web-dev-qa-db-fra.com

WebSockets et proxy Apache: comment configurer mod_proxy_wstunnel?

J'ai :

  1. Apache (v2.4) sur le port 80 de mon serveur pour www.domain1.com, avec mod_proxy et mod_proxy_wstunnelactivé

  2. node.js + socket.io sur le port 3001 du même serveur.

Accéder à www.domain2.com (avec le port 80) redirige en 2. grâce à la méthode décrite ici . J'ai mis cela dans la configuration d'Apache:

<VirtualHost *:80>
    ServerName www.domain2.com
    ProxyPass / http://localhost:3001/
    ProxyPassReverse / http://localhost:3001/
    ProxyPass / ws://localhost:3001/
    ProxyPassReverse / ws://localhost:3001/
</VirtualHost>

Cela fonctionne pour tout, sauf la partie websocket: ws://... ne sont pas transmis comme il se doit par le proxy.

Lorsque j'accède à la page sur www.domain2.com, j'ai:

Impossible to connect ws://www.domain2.com/socket.io/?EIO=3&transport=websocket&sid=n30rqg9AEqZIk5c9AABN.

Question: Comment faire du proxy Apache les WebSockets? 

65
Basj

J'ai finalement réussi à le faire, grâce à ce sujet .

FAIRE:

1) Avoir Apache 2.4 installé (ne fonctionne pas avec 2.2), et faites:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) Avoir nodejs exécuté sur le port 3001

3) Faites ceci dans la configuration Apache

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{REQUEST_URI}  ^/socket.io            [NC]
  RewriteCond %{QUERY_STRING} transport=websocket    [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]

  ProxyPass / http://localhost:3001/
  ProxyPassReverse / http://localhost:3001/
</VirtualHost>

Remarque: si plusieurs services sur le même serveur utilisent des websockets, vous souhaiterez peut-être faire ceci pour les séparer.

112
Basj

Au lieu de filtrer par URL, vous pouvez également filtrer par en-tête HTTP. Cette configuration fonctionnera pour toutes les applications Web utilisant des websockets, même si elles n'utilisent pas socket.io:

<VirtualHost *:80>
  ServerName www.domain2.com

  RewriteEngine On
  RewriteCond %{HTTP:Upgrade} =websocket [NC]
  RewriteRule /(.*)           ws://localhost:3001/$1 [P,L]
  RewriteCond %{HTTP:Upgrade} !=websocket [NC]
  RewriteRule /(.*)           http://localhost:3001/$1 [P,L]

  ProxyPassReverse / http://localhost:3001/
</VirtualHost>
70
cdauth

Peut-être sera-t-il utile… .. Toutes les requêtes sont envoyées via ws au noeud

<VirtualHost *:80>
  ServerName www.domain2.com

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>
15
Sergey

Depuis Socket.IO 1.0 (mai 2014), toutes les connexions commencent par une demande d'interrogation HTTP (plus d'infos ici ). Cela signifie qu'en plus du transfert du trafic WebSocket, vous devez également transférer les requêtes HTTP transport=polling.

La solution ci-dessous devrait rediriger correctement tout le trafic de socket, sans rediriger tout autre trafic.

  1. Activez les mods Apache2 suivants:

    Sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
    
  2. Utilisez ces paramètres dans votre fichier * .conf (par exemple, /etc/Apache2/sites-available/mysite.com.conf). J'ai inclus des commentaires pour expliquer chaque pièce:

    <VirtualHost *:80>
        ServerName www.mydomain.com
    
        # Enable the rewrite engine
        # Requires: Sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
        # In the rules/conds, [NC] means case-insensitve, [P] means proxy
        RewriteEngine On
    
        # socket.io 1.0+ starts all connections with an HTTP polling request
        RewriteCond %{QUERY_STRING} transport=polling       [NC]
        RewriteRule /(.*)           http://localhost:3001/$1 [P]
    
        # When socket.io wants to initiate a WebSocket connection, it sends an
        # "upgrade: websocket" request that should be transferred to ws://
        RewriteCond %{HTTP:Upgrade} websocket               [NC]
        RewriteRule /(.*)           ws://localhost:3001/$1  [P]
    
        # OPTIONAL: Route all HTTP traffic at /node to port 3001
        ProxyRequests Off
        ProxyPass           /node   http://localhost:3001
        ProxyPassReverse    /node   http://localhost:3001
    </VirtualHost>
    
  3. J'ai inclus une section supplémentaire pour le routage du trafic /node que je trouve pratique, voir ici pour plus d'informations.

9
Erik Koopmans

Avec l'aide de ces réponses, j'ai finalement obtenu le proxy inverse pour Node-RED s'exécutant sur un Raspberry Pi avec Ubuntu Mate et Apache2, en utilisant cette configuration de site Apache2:

<VirtualHost *:80>
    ServerName nodered.domain.com
    RewriteEngine On
    RewriteCond %{HTTP:Upgrade} =websocket [NC]
    RewriteRule /(.*)           ws://localhost:1880/$1 [P,L]
    RewriteCond %{HTTP:Upgrade} !=websocket [NC]
    RewriteRule /(.*)           http://localhost:1880/$1 [P,L]
</VirtualHost>

Je devais aussi activer des modules comme celui-ci:

Sudo a2enmod proxy
Sudo a2enmod proxy_http
Sudo a2enmod proxy_wstunnel
6
Otto Paulsen

Ma configuration:

Apache 2.4.10 (sous Debian) NodeJS (version 4.1.1) Application fonctionnant sur le port 3000 acceptant WebSockets sur chemin/api/ws

Comme mentionné ci-dessus par @Basj, assurez-vous que les proxy a2enmod et ws_tunnel sont activés.

Ceci est une capture d'écran du fichier de configuration Apache qui a résolu mon problème:

 enter image description here

J'espère que cela pourra aider.

5
Anwaarullah

Faites ce qui suit pour une application de printemps exécutant du contenu statique, repos et websocket.

Apache est utilisé comme point de terminaison proxy et SSL pour les URI suivants:

  • / app → contenu statique 
  • / api → REST API
  • / api/ws → websocket

Configuration Apache

<VirtualHost *:80>
    ServerName xxx.xxx.xxx    

    ProxyRequests Off
    ProxyVia Off
    ProxyPreserveHost On

    <Proxy *>
         Require all granted
    </Proxy>

    RewriteEngine On

    # websocket 
    RewriteCond %{HTTP:Upgrade}         =websocket                      [NC]
    RewriteRule ^/api/ws/(.*)           ws://localhost:8080/api/ws/$1   [P,L]

    # rest
    ProxyPass /api http://localhost:8080/api
    ProxyPassReverse /api http://localhost:8080/api

    # static content    
    ProxyPass /app http://localhost:8080/app
    ProxyPassReverse /app http://localhost:8080/app 
</VirtualHost>

J'utilise la même configuration vHost pour la configuration SSL, pas besoin de changer quoi que ce soit lié au proxy.

Configuration de printemps

server.use-forward-headers: true
2
Ortwin Angermeier

Pour moi, cela fonctionne après avoir ajouté une seule ligne dans httpd.conf comme ci-dessous (ligne en gras).


<VirtualHost *:80>
    ServerName: xxxxx

    #ProxyPassReverse is not needed
    ProxyPass /log4j ws://localhost:4711/logs
<VirtualHost *:80>

La version d'Apache est 2.4.6 sur CentOS. 

2
Leon

En plus de la réponse principale: si vous avez plusieurs services sur le même serveur qui utilise Websockets, vous pouvez le faire pour les séparer, en utilisant un chemin personnalisé (*). :

Serveur de nœud:

var io = require('socket.io')({ path: '/ws_website1'}).listen(server);

Client HTML:

<script src="/ws_website1/socket.io.js"></script>
...
<script>
var socket = io('', { path: '/ws_website1' });
...

Apache config:

RewriteEngine On

RewriteRule ^/website1(.*)$ http://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteCond %{QUERY_STRING} transport=websocket [NC]
RewriteRule ^(.*)$ ws://localhost:3001$1 [P,L]

RewriteCond %{REQUEST_URI}  ^/ws_website1 [NC]
RewriteRule ^(.*)$ http://localhost:3001$1 [P,L]

(*) Remarque: l'utilisation de la valeur par défaut RewriteCond %{REQUEST_URI} ^/socket.io ne serait pas spécifique à un site Web et les demandes de Websockets seraient mélangées entre différents sites Web!

1
Basj

Pour le transport "polling".

Côté Apache:

<VirtualHost *:80>
    ServerName mysite.com
    DocumentRoot /my/path


    ProxyRequests Off

    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>

    ProxyPass /my-connect-3001 http://127.0.0.1:3001/socket.io
    ProxyPassReverse /my-connect-3001 http://127.0.0.1:3001/socket.io   
</VirtualHost>

Côté client:

var my_socket = new io.Manager(null, {
    Host: 'mysite.com',
    path: '/my-connect-3001'
    transports: ['polling'],
}).socket('/');
0
sNICkerssss

FAIRE:

  1. Avoir Apache 2.4 installé (ne fonctionne pas avec 2.2), a2enmod proxy et a2enmod proxy_wstunnel.load

  2. Faites cela dans la configuration Apache
    il suffit d’ajouter deux lignes dans votre fichier où 8080 est votre port d’exécution Tomcat

    <VirtualHost *:80>
    ProxyPass "/ws2/" "ws://localhost:8080/" 
    ProxyPass "/wss2/" "wss://localhost:8080/"
    
    </VirtualHost *:80>
    
0
Arvind Madhukar

Utilisez ce lien pour une solution parfaite pour ws https://httpd.Apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

Vous devez juste faire ci-dessous l'étape ..

Arrivé à/etc/Apache2/mods-available

Étape 1

Activer le mode proxy_wstunnel.load en utilisant la commande ci-dessous

$ a2enmod proxy_wstunnel.load

Étape 2 

Aller à/etc/Apache2/sites-available

et ajoutez la ligne ci-dessous dans votre fichier .conf à l'intérieur de l'hôte virtuel

ProxyPass "/ ws2 /" "ws: // localhost: 8080 /"

ProxyPass "/ wss2 /" "wss: // localhost: 8080 /"

Remarque: 8080 signifie que votre port Tomcat est en cours d'exécution parce que nous voulons connecter "ws", où notre fichier War mis dans Tomcat et Tomcat servent Apache pour "ws" . Merci

Ma configuration 

ws: //localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver? userid = 4 = Connecté

0
Arvind Madhukar