Wie richtet man NGINX als Reverse Proxy für sichere WebSockets ein?

Veröffentlicht 8. September 2024

Problem: Absicherung von WebSocket-Verbindungen mit NGINX

Das Einrichten eines Reverse Proxy für WebSocket-Verbindungen kann schwierig sein, besonders wenn man es sicher gestalten möchte. NGINX ist ein Webserver, der diese Aufgabe erfüllen kann, aber man muss wissen, wie man ihn richtig konfiguriert.

Konfiguration von NGINX für sicheren WebSocket-Proxy

NGINX-Installation einrichten

Um NGINX für einen sicheren WebSocket-Proxy einzurichten, müssen Sie ihn auf Ihrem Server installieren. Hier sind die Schritte:

  1. Aktualisieren Sie Ihren Paketmanager:

    sudo apt update
  2. Installieren Sie NGINX:

    sudo apt install nginx
  3. Starten Sie den NGINX-Dienst:

    sudo systemctl start nginx
  4. Aktivieren Sie NGINX, damit es beim Systemstart automatisch startet:

    sudo systemctl enable nginx

SSL/TLS-Zertifikat-Konfiguration

Für sichere WebSocket-Verbindungen benötigen Sie SSL/TLS-Zertifikate. So erhalten und konfigurieren Sie diese:

  1. Installieren Sie Certbot für kostenlose Let's Encrypt-Zertifikate:

    sudo apt install certbot python3-certbot-nginx
  2. Beantragen Sie ein Zertifikat für Ihre Domain:

    sudo certbot --nginx -d ihredomain.de
  3. Folgen Sie den Anweisungen, um die Zertifikatinstallation abzuschließen.

NGINX-Konfiguration für WebSocket-Proxy

Nun richten Sie NGINX ein, um WebSocket-Verbindungen zu proxyen:

  1. Öffnen Sie die NGINX-Konfigurationsdatei:

    sudo nano /etc/nginx/sites-available/default
  2. Fügen Sie diese Konfiguration hinzu, um WebSocket-Unterstützung zu aktivieren:

    server {
       listen 443 ssl;
       server_name ihredomain.de;
    
       ssl_certificate /etc/letsencrypt/live/ihredomain.de/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/ihredomain.de/privkey.pem;
    
       location /websocket/ {
           proxy_pass http://backend_host;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
       }
    }

    Ersetzen Sie ihredomain.de durch Ihre Domain und backend_host durch die Adresse Ihres WebSocket-Servers.

  3. Speichern Sie die Datei und beenden Sie den Editor.

  4. Testen Sie die NGINX-Konfiguration:

    sudo nginx -t
  5. Wenn der Test erfolgreich ist, laden Sie NGINX neu:

    sudo systemctl reload nginx

Diese Konfiguration richtet NGINX so ein, dass es auf Port 443 für SSL-Verbindungen lauscht, die zuvor erhaltenen SSL-Zertifikate verwendet und WebSocket-Verbindungen zu Ihrem Backend-Server weiterleitet.

Beispiel: Umgang mit WebSocket-Timeouts

Um zu verhindern, dass WebSocket-Verbindungen unterbrochen werden, können Sie diese Direktiven zu Ihrer NGINX-Konfiguration hinzufügen:

location /websocket/ {
    proxy_pass http://backend_host;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
    proxy_send_timeout 3600s;
}

Dies setzt die Lese- und Sendetimeouts auf 1 Stunde (3600 Sekunden), was bei langlebigen WebSocket-Verbindungen hilft.

Implementierung von WebSocket-Proxy-Einstellungen

Proxy Pass-Direktiven

So richten Sie die proxy_pass-Direktive für WebSocket-Verkehr in NGINX ein:

  1. Öffnen Sie Ihre NGINX-Konfigurationsdatei:

    sudo nano /etc/nginx/sites-available/default
  2. Fügen Sie im location-Block für WebSocket-Verbindungen die proxy_pass-Direktive hinzu:

    location /websocket/ {
       proxy_pass http://ihr_websocket_server;
    }

    Ersetzen Sie "ihr_websocket_server" durch die Adresse Ihres WebSocket-Servers.

Tipp: SSL für WebSocket-Verbindungen verwenden

Um Ihre WebSocket-Verbindungen abzusichern, verwenden Sie SSL/TLS. Ändern Sie Ihre proxy_pass-Direktive, um HTTPS zu verwenden:

location /websocket/ {
    proxy_pass https://ihr_websocket_server;
}

Dies hilft, die zwischen Client und Server übertragenen Daten zu schützen.

Header-Modifikationen

So richten Sie die Header für die WebSocket-Kommunikation ein:

  1. Fügen Sie im selben location-Block diese Header-Modifikationen hinzu:

    location /websocket/ {
       proxy_pass http://ihr_websocket_server;
       proxy_set_header Host $host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
    }

    Diese Header helfen, die ursprünglichen Client-Informationen beim Durchlaufen des Proxys beizubehalten.

Handhabung von Connection Upgrades

So verwalten Sie WebSocket-Verbindungs-Upgrades durch NGINX:

  1. Fügen Sie diese Direktiven zu Ihrem location-Block hinzu:

    location /websocket/ {
       proxy_pass http://ihr_websocket_server;
       proxy_http_version 1.1;
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
    }

    Die 'Upgrade'- und 'Connection'-Header sind für den WebSocket-Protokoll-Handshake erforderlich.

  2. Speichern Sie die Datei und beenden Sie den Editor.

  3. Testen Sie Ihre NGINX-Konfiguration:

    sudo nginx -t
  4. Wenn der Test erfolgreich ist, laden Sie NGINX neu:

    sudo systemctl reload nginx

Diese Einstellungen ermöglichen es NGINX, WebSocket-Verbindungen zu handhaben, einschließlich des initialen Handshakes und der Kommunikation.

Feinabstimmung von NGINX für optimale WebSocket-Leistung

Timeout-Einstellungen

Um langlebige WebSocket-Verbindungen zu handhaben, passen Sie die proxy_read_timeout-Einstellung in Ihrer NGINX-Konfiguration an:

  1. Öffnen Sie Ihre NGINX-Konfigurationsdatei:

    sudo nano /etc/nginx/sites-available/default
  2. Fügen Sie in Ihrem WebSocket-Location-Block die proxy_read_timeout-Direktive hinzu oder ändern Sie sie:

    location /websocket/ {
       proxy_pass http://ihr_websocket_server;
       proxy_read_timeout 3600s;
    }

    Dies setzt den Lese-Timeout auf 1 Stunde (3600 Sekunden), was für die meisten WebSocket-Anwendungen gut ist.

  3. Sie können auch proxy_send_timeout hinzufügen:

    proxy_send_timeout 3600s;

Optimierung der Puffergröße

Um die Puffergrößen für WebSocket-Verkehr zu optimieren:

  1. Fügen Sie im selben Location-Block diese Direktiven hinzu:

    location /websocket/ {
       proxy_pass http://ihr_websocket_server;
       proxy_buffering off;
       proxy_buffer_size 4k;
       proxy_buffers 4 4k;
    }
    • proxy_buffering off: Dies schaltet die Pufferung von Antworten vom Proxy-Server aus, was oft gut für WebSocket-Verbindungen ist.
    • proxy_buffer_size 4k: Dies setzt die Größe des Puffers für das Lesen des ersten Teils der Antwort vom Proxy-Server.
    • proxy_buffers 4 4k: Dies legt die Anzahl und Größe der Puffer für eine einzelne Verbindung fest.
  2. Wenn Sie große Nachrichten erwarten, müssen Sie diese Werte möglicherweise erhöhen:

    proxy_buffer_size 8k;
    proxy_buffers 8 8k;
  3. Speichern Sie die Datei und beenden Sie den Editor.

  4. Testen Sie Ihre NGINX-Konfiguration:

    sudo nginx -t
  5. Wenn der Test erfolgreich ist, laden Sie NGINX neu:

    sudo systemctl reload nginx

Testen und Fehlerbehebung

Überprüfung sicherer WebSocket-Verbindungen

So testen Sie Ihre WebSocket-Proxy-Einrichtung:

  1. Verwenden Sie Online-WebSocket-Testtools:

    • Besuchen Sie websocket.org/echo.html
    • Geben Sie Ihre WebSocket-URL ein (wss://ihredomain.de/websocket)
    • Klicken Sie auf "Connect" und prüfen Sie, ob die Verbindung funktioniert
  2. Verwenden Sie Kommandozeilen-Tools:

    • Installieren Sie wscat: npm install -g wscat
    • Verbinden Sie sich mit Ihrem WebSocket-Server: wscat -c wss://ihredomain.de/websocket
    • Senden Sie eine Nachricht und prüfen Sie, ob Sie eine Antwort erhalten
  3. Überprüfen Sie NGINX-Logs:

    • Fehlerprotokolle anzeigen: sudo tail -f /var/log/nginx/error.log
    • Zugriffsprotokoll

e anzeigen: sudo tail -f /var/log/nginx/access.log

  1. Verwenden Sie Browser-Entwicklertools:
    • Öffnen Sie Ihre Webanwendung
    • Gehen Sie zum Netzwerk-Tab
    • Filtern Sie nach WebSocket-Verbindungen
    • Prüfen Sie, ob die Verbindung aufgebaut wird und Nachrichten gesendet/empfangen werden

Tipp: Browser-Konsole für WebSocket-Debugging verwenden

Öffnen Sie die Konsole Ihres Browsers (normalerweise F12 oder Strg+Umschalt+I) und fügen Sie den folgenden Code hinzu, um WebSocket-Ereignisse zu überwachen:

var ws = new WebSocket("wss://ihredomain.de/websocket");
ws.onopen = function() { console.log("WebSocket verbunden"); };
ws.onmessage = function(evt) { console.log("Empfangen: " + evt.data); };
ws.onclose = function() { console.log("WebSocket geschlossen"); };
ws.onerror = function(err) { console.log("WebSocket-Fehler: ", err); };

Dies protokolliert WebSocket-Ereignisse in Echtzeit und hilft Ihnen bei der Fehlersuche bei Verbindungsproblemen.

Häufige Probleme und Lösungen

  1. Verbindung verweigert:

    • Prüfen Sie, ob Ihr WebSocket-Server läuft
    • Stellen Sie sicher, dass die proxy_pass-Direktive auf die richtige Adresse und den richtigen Port zeigt
  2. SSL-Zertifikatfehler:

    • Stellen Sie sicher, dass Ihre SSL-Zertifikate gültig und nicht abgelaufen sind
    • Überprüfen Sie, ob die Zertifikatdateien in der NGINX-Konfiguration korrekt referenziert sind
  3. WebSocket-Handshake schlägt fehl:

    • Überprüfen Sie, ob die Upgrade- und Connection-Header korrekt gesetzt sind
    • Stellen Sie sicher, dass proxy_http_version auf 1.1 gesetzt ist
  4. Timeouts bei lang laufenden Verbindungen:

    • Erhöhen Sie die Werte für proxy_read_timeout und proxy_send_timeout
    • Implementieren Sie einen Ping-Pong-Mechanismus in Ihrer WebSocket-Anwendung
  5. Große Nachrichten werden nicht übertragen:

    • Erhöhen Sie client_max_body_size in Ihrer NGINX-Konfiguration
    • Passen Sie proxy_buffer_size und proxy_buffers bei Bedarf an
  6. Cross-Origin Resource Sharing (CORS)-Probleme:

    • Fügen Sie Header hinzu, um CORS zu erlauben:
      add_header 'Access-Control-Allow-Origin' '*';
      add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
      add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
  7. HTTP/2-Kompatibilitätsprobleme:

    • Wenn Sie HTTP/2 verwenden, fügen Sie proxy_set_header Connection ""; zu Ihrem Location-Block hinzu