NGINX als WebSocket-Proxy

NGINX | 16. Mai 2014

Das WebSocket-Protokoll ermöglicht die Erstellung von Webanwendungen, die eine bidirektionale Echtzeitkommunikation zwischen Clients und Servern unterstützen. Als Bestandteil von HTML5 erleichtert WebSocket die Entwicklung solcher Anwendungen im Vergleich zu den bisher verfügbaren Methoden erheblich. Die meisten modernen Browser unterstützen WebSocket, darunter Chrome, Firefox, Internet Explorer, Opera und Safari. Auch immer mehr Frameworks für Serveranwendungen bieten Unterstützung für WebSocket.

Für den produktiven Einsatz in Unternehmen, bei dem mehrere WebSocket-Server für hohe Leistung und Verfügbarkeit benötigt werden, ist eine Load-Balancing-Schicht erforderlich, die das WebSocket-Protokoll versteht. NGINX unterstützt WebSocket seit Version 1.3 und kann als Reverse-Proxy fungieren sowie das Load-Balancing für WebSocket-Anwendungen übernehmen. (Auch alle Versionen von NGINX Plus unterstützen WebSocket.)

Sehen Sie sich aktuelle Leistungstests zur Skalierbarkeit von NGINX beim Lastenausgleich von WebSocket-Verbindungen an.

Das WebSocket-Protokoll unterscheidet sich vom HTTP-Protokoll, der WebSocket-Handshake ist jedoch mit HTTP kompatibel und nutzt den HTTP-Upgrade-Mechanismus, um die Verbindung von HTTP auf WebSocket umzustellen. Dadurch lassen sich WebSocket-Anwendungen leichter in bestehende Infrastrukturen integrieren. Beispielsweise können WebSocket-Anwendungen die standardmäßigen HTTP-Ports 80 und 443 verwenden, sodass bestehende Firewall-Regeln weiterhin genutzt werden können.

Eine WebSocket-Anwendung hält eine dauerhafte Verbindung zwischen Client und Server offen und erleichtert so die Entwicklung von Echtzeitanwendungen. Der HTTP-Upgrade-Mechanismus, mit dem die Verbindung von HTTP auf WebSocket umgestellt wird, verwendet die Header Upgrade und Connection. Die Unterstützung von WebSocket stellt einen Reverse-Proxy-Server vor einige Herausforderungen. Zum einen ist WebSocket ein Hop-by-Hop-Protokoll. Wenn ein Proxyserver eine Upgrade-Anforderung von einem Client abfängt, muss er daher eine eigene Upgrade-Anforderung mit den entsprechenden Headern an den Backend-Server senden. Da WebSocket-Verbindungen im Gegensatz zu den typischen kurzlebigen HTTP-Verbindungen außerdem langlebig sind, muss der Reverse-Proxy zulassen, dass diese Verbindungen offen bleiben, anstatt sie zu schließen, weil sie inaktiv zu sein scheinen.

NGINX unterstützt WebSocket, indem es den Aufbau eines Tunnels zwischen einem Client und einem Backend-Server ermöglicht. Damit NGINX die Upgrade-Anfrage des Clients an den Backend-Server senden kann, müssen die Header Upgrade und Connection explizit festgelegt werden, wie in diesem Beispiel:

location /wsapp/ {    proxy_pass http://wsbackend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
}

Sobald dies erledigt ist, behandelt NGINX die Verbindung als WebSocket-Verbindung.

NGINX-WebSocket-Beispiel

Das folgende praktische Beispiel zeigt NGINX in der Funktion als WebSocket-Proxy. In diesem Beispiel wird ws verwendet, eine auf Node.js basierende WebSocket-Implementierung. NGINX fungiert als Reverse-Proxy für eine einfache WebSocket-Anwendung, die ws und Node.js verwendet. Diese Anleitung wurde mit Ubuntu 13.10 und CentOS 6.5 getestet, muss für andere Betriebssysteme und Versionen jedoch möglicherweise angepasst werden. In diesem Beispiel lautet die IP-Adresse des WebSocket-Servers 192.168.100.10 und die des NGINX-Servers 192.168.100.20.

  1. Wenn Sie Node.js und npm noch nicht installiert haben, führen Sie den folgenden Befehl aus:
    • Für Debian und Ubuntu:
$ sudo apt-get install nodejs npm
  • Für RHEL und CentOS:
$ sudo yum install nodejs npm
  1. Node.js wird unter Ubuntu als „nodejs“ und unter CentOS als „node“ installiert. Im Beispiel wird „node“ verwendet, daher müssen wir unter Ubuntu einen symbolischen Link von „nodejs“ zu „node“ erstellen:
$ ln -s /usr/bin/nodejs /usr/local/bin/node
  1. Um ws zu installieren, führen Sie den folgenden Befehl aus:
$ sudo npm install ws
  1. Hinweis: Wenn die Fehlermeldung „Error: failed to fetch from registry: ws“ angezeigt wird, führen Sie den folgenden Befehl aus, um das Problem zu beheben:
$ sudo npm config set registry http://registry.npmjs.org/
  1. Führen Sie anschließend den Befehl „sudo npm install ws“ erneut aus.
  2. ws enthält das Programm /root/node_modules/ws/bin/wscat, das wir für unseren Client verwenden werden. Wir müssen jedoch ein Programm erstellen, das als Server fungiert. Erstellen Sie eine Datei namens server.js mit folgendem Inhalt:
console.log("Server started");
var Msg = '';
var WebSocketServer = require('ws').Server
    , wss = new WebSocketServer({port: 8010});
    wss.on('connection', function(ws) {
        ws.on('message', function(message) {
        console.log('Received from client: %s', message);
        ws.send('Server received from client: ' + message);
    });
 });
  1. Führen Sie den folgenden Befehl aus, um das Serverprogramm zu starten:
$ node server.js
  1. Der Server gibt zunächst die Meldung "Server started" aus und lauscht dann auf Port 8010, während er darauf wartet, dass sich ein Client mit ihm verbindet. Wenn er eine Clientanfrage empfängt, gibt er sie zurück und sendet dem Client eine Nachricht mit dem Inhalt der empfangenen Nachricht. Damit NGINX diese Anfragen als Proxy weiterleitet, erstellen wir die folgende Konfiguration. Wir fügen den map-Block hinzu, damit der Connection-Header korrekt auf close gesetzt wird, wenn der Upgrade-Header in der Anfrage auf '' gesetzt ist.
http {
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }
 
    upstream websocket {
        server 192.168.100.10:8010;
    }
 
    server {
        listen 8020;
        location / {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
        }
    }
}
  1. NGINX lauscht auf Port 8020 und leitet Anfragen an den Backend-WebSocket-Server weiter. Die proxy_set_header-Direktiven ermöglichen NGINX die korrekte Verarbeitung des WebSocket-Protokolls.
  2. Um den Server zu testen, führen wir wscat als Client aus:
$ /root/node_modules/ws/bin/wscat --connect ws://192.168.100.20:8020
  1. wscat stellt über den NGINX-Proxy eine Verbindung zum WebSocket-Server her. Wenn Sie eine Nachricht eingeben, die wscat an den Server senden soll, sehen Sie, wie sie auf dem Server ausgegeben wird. Anschließend erscheint eine Nachricht vom Server auf dem Client. Hier sehen Sie eine Beispielinteraktion: Server: Client: $node server.js
    Server gestartet 
     

    wscat --connect ws://192.168.100.20:8020
    Verbunden (zum Beenden STRG+C drücken)
    > Hallo
    Vom Client empfangen: Hallo < Server hat vom Client empfangen: Hallo Hier sehen wir, dass Client und Server über NGINX, das als Proxy fungiert, miteinander kommunizieren können. Nachrichten können so lange in beide Richtungen gesendet werden, bis entweder der Client oder der Server die Verbindung trennt. Damit NGINX WebSocket ordnungsgemäß verarbeitet, müssen lediglich die Header korrekt festgelegt werden, um die Upgrade-Anfrage zu verarbeiten, durch die die Verbindung von HTTP auf WebSocket umgestellt wird.

Weiterführende Informationen


Teilen
Schlagwörter: Tech, F5 NGINX, 2014

Über den Autor

Rick Nelson
Rick NelsonRegional Vice President, Solution Engineering

Weitere Blogbeiträge von Rick Nelson

Ähnliche Blogbeiträge

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln
NGINX | 23.08.2022

Die Zukunft von NGINX: Zurück zu unseren Open-Source-Wurzeln

Beim NGINX Sprint 2022 besinnen wir uns auf unsere Open-Source-Wurzeln. Erfahren Sie mehr über die Initiativen, die wir im kommenden Jahr verfolgen, und teilen Sie uns mit, was Sie sich wünschen.

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen
NGINX | 08.09.2021

Ein Leitfaden zur Auswahl eines Ingress-Controllers, Teil 1: Ermitteln Sie Ihre Anforderungen

Ein Ingress-Controller kann eines der leistungsstärksten Tools in Ihrem Kubernetes-Stack sein. Erfahren Sie, wie Sie Ihre Ingress-Anforderungen ermitteln, um die beste Option auszuwählen.

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet
NGINX | 16.08.2021

Bereitstellung des NGINX Ingress Controllers auf Amazon EKS: So haben wir getestet

Wir haben kürzlich den Lösungsleitfaden zum NGINX Ingress Controller um Empfehlungen zur Dimensionierung für Amazon Elastic Kubernetes Service (EKS) ergänzt. In diesem Blogbeitrag erläutern wir, wie wir diese Empfehlungen erarbeitet haben, und stellen Ihnen alle Informationen zur Verfügung, die Sie benötigen, um selbst ähnliche Tests durchzuführen.

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77
NGINX | 12.12.2018

Protokollierung des Datenverkehrs zwischen NGINX und Upstream-Servern bei CDN77

Bei der Fehlersuche bei Datenverkehrsproblemen zwischen NGINX und Upstream-Servern konnte CDN77 die benötigten Daten nur aus dem Fehlerprotokoll mit aktivierter Debug-Ausgabe beziehen, was die Leistung beeinträchtigt und riesige Dateien erzeugt. Daher entwickelte das Team ein neues benutzerdefiniertes Modul, das ausschließlich die benötigten Daten protokolliert.

Ankündigung von NGINX Plus R16
NGINX | 05.09.2018

Ankündigung von NGINX Plus R16

NGINX Plus R16 ist eine einheitliche, elastische Ingress- und Egress-Schicht für Anwendungen, die die Funktionen eines Load Balancers, API-Gateways und einer WAF vereint und neue Features wie clusterfähige Ratenbegrenzung, Schlüssel-Wert-Speicher, „Random with Two Choices“, verbessertes UDP-Load-Balancing und vieles mehr bietet.

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing
NGINX | 13.10.2016

5 Gründe für den Umstieg auf softwarebasiertes Load Balancing

Entdecken Sie fünf Gründe für den Wechsel zu einem softwarebasierten Load Balancer wie NGINX Plus, darunter Kosteneinsparungen, die Einführung von DevOps und eine einheitliche Lösung für alle Umgebungen.