WebSockets und Apache-Proxy: Wie konfiguriere ich mod_proxy_wstunnel?

98

Ich habe :

  1. Apache(v2.4) auf Port 80 meines Servers für www.domain1.com, wobei mod_proxy und mod_proxy_wstunnel aktiviert sind

  2. node.js + socket.io auf Port 3001 desselben Servers.

Der Zugriff www.domain2.com(mit Port 80) leitet dank der hier beschriebenen Methode zu 2. weiter . Ich habe dies in der Apache-Konfiguration festgelegt:

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

Es funktioniert für alles, außer für den Websocket-Teil: Sie ws://...werden nicht wie vom Proxy übertragen übertragen.

Wenn ich auf die Seite zugreife www.domain2.com, habe ich:

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

Frage: Wie mache ich Apache-Proxy auch zu WebSockets?

Basj
quelle

Antworten:

160

Dank dieses Themas habe ich es endlich geschafft .

MACHEN:

1) Haben Sie Apache 2.4 installiert (funktioniert nicht mit 2.2) und tun Sie Folgendes:

a2enmod proxy
a2enmod proxy_http
a2enmod proxy_wstunnel

2) nodejsAuf Port 3001 laufen lassen

3) Tun Sie dies in der Apache-Konfiguration

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

Hinweis: Wenn Sie mehr als einen Dienst auf demselben Server haben, der Websockets verwendet, möchten Sie dies möglicherweise tun , um sie zu trennen.

Basj
quelle
FWIW, Apache 2.4 in CentOS 7.1 hat diesen Fehler, daher erkennt das Umschreiben das Protokoll ws: // nicht und stellt die Domäne vor dem Senden der Unteranforderung voran. Sie können sich selbst testen, indem Sie das [P] roxy-Flag in [R] edirect ändern.
Andor
3
Ich bekomme dabei immer noch 502 schlechte Gateways für meine ws: // Routen. Ausführen von Apache 2.4 unter Ubuntu 14.04
Alex Muro
1
Dies funktioniert, da auch der gesamte HTTP-Verkehr weitergeleitet wird. Wenn Sie jedoch nur Ihren Socket-Verkehr weiterleiten möchten, beachten Sie bitte, dass Socket.io die Kommunikation mit einer HTTP-Abfrageanforderung startet. Mehr Infos hier .
Erik Koopmans
4
Wie kann ich von 443 wss nach ws weiterleiten? ändert sich das Umschreiben der Sekunde?
Hernán Eche
1
Der Zustand RewriteCond %{QUERY_STRING} transport=websocket [NC]hat bei mir nicht richtig funktioniert. Schlagen vor, RewriteCond %{HTTP:Upgrade} =websocket [NC]stattdessen zu verwenden .
Martin
98

Anstatt nach URL zu filtern, können Sie auch nach HTTP-Header filtern. Diese Konfiguration funktioniert für alle Webanwendungen, die Websockets verwenden, auch wenn sie nicht socket.io verwenden:

<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>
cdauth
quelle
Dies funktioniert gut für mich, aber ich vertrete einen Unterpfad und habe festgestellt, dass es wichtig ist, die ^ Anker hinzuzufügen, da der Regex nach einem Teilstring sucht. ZB RewriteRule ^ [^ /] * / foo /(.*) http: // $ {FOO_HOST} / $ 1 [P, L] (andernfalls wird / bar / foo auch an denselben Ort wie / foo geleitet)
Steve Lilly
Diese Konfiguration funktioniert am besten in der Alibaba Cloud. Außerdem wird der Fehler net behoben :: ERR_RESPONSE_HEADERS_TRUNCATED "Hoffe, jemand findet dies nützlich.
Mike Musni
Mit SignalR kann ich sagen, dass dies für mich am besten funktioniert hat +1 Danke
Vojtěch Mráz
18

Kann nützlich sein. Nur alle Anfragen werden über ws an den Knoten gesendet

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

  <Location "/">
    ProxyPass "ws://localhost:3001/"
  </Location>
</VirtualHost>
Sergey
quelle
Danke @Sergey. Dies hat mir geholfen, als ich nur den direkten Pfad verwendet habe, auf den ws verweist, anstatt alles an den Dokumentstamm weiterzuleiten. Ich habe in einer Antwort unten gezeigt, was ich zum Nutzen anderer getan habe.
Anwaarullah
Diese Antwort funktioniert für einfache Web-Sockets (kein socket.io), daher ist dies für mich die bessere Antwort
Tomas
Genial! Dies funktionierte sofort für mich, während die anderen Umschreibungs- und Proxy-Versuche mein Problem nicht lösten.
Stephan
Danke dir!! Perfekt für den grundlegenden Anwendungsfall, nur eine einfache Web-Socket mit ws: //
Antonia Blair
16

Ab Socket.IO 1.0 (Mai 2014) beginnen alle Verbindungen mit einer HTTP-Abfrageanforderung (weitere Informationen hier ). Das bedeutet, dass Sie zusätzlich zur Weiterleitung des WebSocket-Datenverkehrs alle transport=pollingHTTP-Anforderungen weiterleiten müssen .

Die folgende Lösung sollte den gesamten Socket-Verkehr korrekt umleiten, ohne anderen Verkehr umzuleiten.

  1. Aktiviere die folgenden Apache2 Mods:

    sudo a2enmod proxy rewrite proxy_http proxy_wstunnel
  2. Verwenden Sie diese Einstellungen in Ihrer * .conf-Datei (z /etc/apache2/sites-available/mysite.com.conf. B. ). Ich habe Kommentare beigefügt, um jedes Stück zu erklären:

    <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. Ich habe einen zusätzlichen Abschnitt zum Weiterleiten von /nodeDatenverkehr hinzugefügt , den ich als nützlich empfinde. Weitere Informationen finden Sie hier .

Erik Koopmans
quelle
1
Das funktioniert perfekt für mich. Beachten Sie, dass , wenn Ihre Anfragen in zu einer URL kommen andere als root, können Sie zBRewriteRule /path/(.*)
Rob Gwynn-Jones
8

Mit Hilfe dieser Antworten habe ich endlich einen Reverse-Proxy für Node-RED erhalten, der auf einem Raspberry Pi mit Ubuntu Mate und Apache2 ausgeführt wird. Dabei wurde diese Apache2-Site-Konfiguration verwendet:

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

Ich musste auch Module wie diese aktivieren:

sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod proxy_wstunnel
Otto Paulsen
quelle
7

Bei mir funktioniert es, nachdem nur eine Zeile in httpd.conf wie unten hinzugefügt wurde (fette Zeile).


<VirtualHost *:80>
    ServerName: xxxxx

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

Die Apache-Version ist 2.4.6 unter CentOS.

Leon
quelle
5

Mein Setup:

  • Apache 2.4.10 (läuft unter Debian)
  • Node.js (Version 4.1.1) App, die auf Port 3000 ausgeführt wird und WebSockets im Pfad akzeptiert /api/ws

Stellen Sie, wie oben von @Basj erwähnt, sicher, dass a2enmod-Proxy und ws_tunnel aktiviert sind.

Dies ist ein Screenshot der Apache-Konfigurationsdatei, die mein Problem gelöst hat:

Apache-Konfiguration

Der relevante Teil als Text:

<VirtualHost *:80>
  ServerName *******
  ServerAlias *******
  ProxyPass / http://localhost:3000/
  ProxyPassReverse / http://localhost:3000/

  <Location "/api/ws">
      ProxyPass "ws://localhost:3000/api/ws"
  </Location>
</VirtualHost>

Hoffentlich hilft das.

Anwaarullah
quelle
Ich habe Probleme beim Einrichten meiner App mit einer bevorzugten URL anstelle der Standard-URL. Würde es Ihnen etwas ausmachen, mir zu helfen? (Ich sitze auf einem Lack-Cache-Server)
Josh
6
Könnten Sie anstelle von Screenshots kopieren / einfügen? Vielen Dank im Voraus, es würde die Lesbarkeit verbessern.
Basj
3

Führen Sie die folgenden Schritte für eine Federanwendung aus, auf der statische, Ruhe- und Websocket-Inhalte ausgeführt werden.

Der Apache wird als Proxy und SSL-Endpunkt für die folgenden URIs verwendet:

  • / app → statischer Inhalt
  • / api → REST-API
  • / api / ws → Websocket

Apache-Konfiguration

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

Ich verwende dieselbe vHost-Konfiguration für die SSL-Konfiguration, ohne dass Proxy-bezogene Änderungen erforderlich sind.

Federkonfiguration

server.use-forward-headers: true
Ortwin Angermeier
quelle
Verwenden Sie ein Standort-Tag, um Standorte zu trennen, dh: <Standort / App> ProxyPass localhost: 8080 / app ProxyPassReverse localhost: 8080 / app </ Standort>
CrazyMerlin
2

Verwenden Sie diesen Link für eine perfekte Lösung für ws https://httpd.apache.org/docs/2.4/mod/mod_proxy_wstunnel.html

Sie müssen nur unter Schritt tun ..

Gehe zu /etc/apache2/mods-available

Schritt 1

Aktivieren Sie mode proxy_wstunnel.loadmit dem folgenden Befehl

$a2enmod proxy_wstunnel.load

Schritt 2

Gehe zu /etc/apache2/sites-available

und fügen Sie die folgende Zeile in Ihre .conf-Datei innerhalb des virtuellen Hosts ein

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

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

Hinweis: 8080 bedeutet, dass Ihr Tomcat ausgeführt wird, da wir eine Verbindung herstellen möchten, für die wsunsere in Tomcat und Tomcat geputte War-Datei Apache bereitstelltws . Danke

Meine Konfiguration

ws://localhost/ws2/ALLCAD-Unifiedcommunication-1.0/chatserver?userid=4 =Connected
Arvind Madhukar
quelle
Entschuldigung, ich verstehe das nicht wirklich (besonders deinen letzten Satz). Können Sie die Formatierung der Antwort verbessern und Details für Personen hinzufügen, die nicht alles wissen, was Sie erwähnen?
Basj
Was ist Tomcat @ArvindMadhukar?
Basj
1

Zum "Polling" -Transport.

Apache Seite:

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

Client-Seite:

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

Zusätzlich zur Hauptantwort: Wenn Sie mehr als einen Dienst auf demselben Server haben, der Websockets verwendet, möchten Sie diese möglicherweise mithilfe eines benutzerdefinierten Pfads (*) trennen :

Knotenserver:

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-Konfiguration:

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]

(*) Hinweis: Die Verwendung der Standardeinstellung ist RewriteCond %{REQUEST_URI} ^/socket.ionicht spezifisch für eine Website, und Websockets-Anfragen werden zwischen verschiedenen Websites verwechselt!

Basj
quelle
0

MACHEN:

  1. Habe Apache 2.4 installiert (funktioniert nicht mit 2.2) a2enmod proxyunda2enmod proxy_wstunnel.load

  2. Fügen Sie dazu in der Apache-Konfiguration
    einfach zwei Zeilen in Ihre Datei ein, wobei 8080 Ihr Tomcat-Laufport ist

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