Come configurare NGINX come reverse proxy per WebSocket sicuri?

Pubblicato 8 settembre 2024

Problema: Proteggere le Connessioni WebSocket con NGINX

Configurare un proxy inverso per le connessioni WebSocket può essere complicato, soprattutto quando si vuole mantenerlo sicuro. NGINX è un server web che può svolgere questo compito, ma è necessario sapere come configurarlo correttamente.

Configurazione di NGINX per un Proxy WebSocket Sicuro

Installazione di NGINX

Per configurare NGINX come proxy sicuro per WebSocket, è necessario installarlo sul server. Ecco i passaggi:

  1. Aggiorna il gestore dei pacchetti:

    sudo apt update
  2. Installa NGINX:

    sudo apt install nginx
  3. Avvia il servizio NGINX:

    sudo systemctl start nginx
  4. Abilita NGINX all'avvio del sistema:

    sudo systemctl enable nginx

Configurazione del Certificato SSL/TLS

Per connessioni WebSocket sicure, sono necessari certificati SSL/TLS. Ecco come ottenerli e configurarli:

  1. Installa Certbot per ottenere certificati gratuiti Let's Encrypt:

    sudo apt install certbot python3-certbot-nginx
  2. Ottieni un certificato per il tuo dominio:

    sudo certbot --nginx -d tuodominio.com
  3. Segui le istruzioni per completare l'installazione del certificato.

Configurazione di NGINX per il Proxy WebSocket

Ora, configura NGINX per fare da proxy alle connessioni WebSocket:

  1. Apri il file di configurazione di NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. Aggiungi questa configurazione per abilitare il supporto WebSocket:

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

    Sostituisci tuodominio.com con il tuo dominio e host_backend con l'indirizzo del tuo server WebSocket.

  3. Salva il file ed esci dall'editor.

  4. Testa la configurazione di NGINX:

    sudo nginx -t
  5. Se il test passa, ricarica NGINX:

    sudo systemctl reload nginx

Questa configurazione imposta NGINX per ascoltare sulla porta 443 per connessioni SSL, utilizzare i certificati SSL ottenuti in precedenza e fare da proxy alle connessioni WebSocket verso il tuo server backend.

Esempio: Gestione dei Timeout WebSocket

Per evitare che le connessioni WebSocket vadano in timeout, puoi aggiungere queste direttive alla tua configurazione NGINX:

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

Questo imposta i timeout di lettura e invio a 1 ora (3600 secondi), il che aiuta a mantenere le connessioni WebSocket di lunga durata.

Implementazione delle Impostazioni del Proxy WebSocket

Direttive Proxy Pass

Per configurare la direttiva proxy_pass per il traffico WebSocket in NGINX:

  1. Apri il file di configurazione NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. Nel blocco location per le connessioni WebSocket, aggiungi la direttiva proxy_pass:

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

    Sostituisci "tuo_server_websocket" con l'indirizzo del tuo server WebSocket.

Suggerimento: Usa SSL per le Connessioni WebSocket

Per proteggere le tue connessioni WebSocket, usa SSL/TLS. Modifica la direttiva proxy_pass per usare HTTPS:

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

Questo aiuta a proteggere i dati trasmessi tra il client e il server.

Modifiche agli Header

Per configurare gli header per la comunicazione WebSocket:

  1. Nello stesso blocco location, aggiungi queste modifiche agli header:

    location /websocket/ {
       proxy_pass http://tuo_server_websocket;
       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;
    }

    Questi header aiutano a mantenere le informazioni originali del client quando passano attraverso il proxy.

Gestione dell'Upgrade della Connessione

Per gestire gli upgrade delle connessioni WebSocket attraverso NGINX:

  1. Aggiungi queste direttive al tuo blocco location:

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

    Gli header 'Upgrade' e 'Connection' sono necessari per l'handshake del protocollo WebSocket.

  2. Salva il file ed esci dall'editor.

  3. Testa la tua configurazione NGINX:

    sudo nginx -t
  4. Se il test ha successo, ricarica NGINX:

    sudo systemctl reload nginx

Queste impostazioni permettono a NGINX di gestire le connessioni WebSocket, inclusi l'handshake iniziale e la comunicazione.

Ottimizzazione di NGINX per Prestazioni WebSocket Ottimali

Impostazioni di Timeout

Per gestire connessioni WebSocket di lunga durata, regola l'impostazione proxy_read_timeout nella tua configurazione NGINX:

  1. Apri il file di configurazione NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. Nel tuo blocco location WebSocket, aggiungi o modifica la direttiva proxy_read_timeout:

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

    Questo imposta il timeout di lettura a 1 ora (3600 secondi), che va bene per la maggior parte delle applicazioni WebSocket.

  3. Puoi anche aggiungere proxy_send_timeout:

    proxy_send_timeout 3600s;

Ottimizzazione della Dimensione del Buffer

Per ottimizzare le dimensioni del buffer per il traffico WebSocket:

  1. Nello stesso blocco location, aggiungi queste direttive:

    location /websocket/ {
       proxy_pass http://tuo_server_websocket;
       proxy_buffering off;
       proxy_buffer_size 4k;
       proxy_buffers 4 4k;
    }
    • proxy_buffering off: Disattiva il buffering delle risposte dal server proxy, spesso utile per le connessioni WebSocket.
    • proxy_buffer_size 4k: Imposta la dimensione del buffer per leggere la prima parte della risposta dal server proxy.
    • proxy_buffers 4 4k: Imposta il numero e la dimensione dei buffer per una singola connessione.
  2. Se ti aspetti messaggi grandi, potresti dover aumentare questi valori:

    proxy_buffer_size 8k;
    proxy_buffers 8 8k;
  3. Salva il file ed esci dall'editor.

  4. Testa la tua configurazione NGINX:

    sudo nginx -t
  5. Se il test passa, ricarica NGINX:

    sudo systemctl reload nginx

Test e Risoluzione dei Problemi

Verifica delle Connessioni WebSocket Sicure

Per testare la configurazione del tuo proxy WebSocket:

  1. Usa strumenti di test WebSocket online:

    • Visita websocket.org/echo.html
    • Inserisci l'URL del tuo WebSocket (wss://tuodominio.com/websocket)
    • Clicca su "Connect" e verifica se la connessione funziona
  2. Usa strumenti da riga di comando:

    • Installa wscat: npm install -g wscat
    • Connettiti al tuo server WebSocket: wscat -c wss://tuodominio.com/websocket
    • Invia un messaggio e controlla se ricevi una risposta
  3. Controlla i log di NGINX:

    • Visualizza i log degli errori: sudo tail -f /var/log/nginx/error.log
    • Visualizza i log di accesso: sudo tail -f /var/log/nginx/access.log
  4. Usa gli strumenti di sviluppo del browser:

    • Apri la tua applicazione web
    • Vai alla scheda Network
    • Filtra le connessioni WebSocket
    • Verifica se la connessione è stabilita e i messaggi vengono inviati/ricevuti

Suggerimento: Usa la Console del Browser per il Debug WebSocket

Apri la console del tuo browser (di solito F12 o Ctrl+Shift+I) e aggiungi il seguente codice per monitorare gli eventi WebSocket:

var ws = new WebSocket("wss://tuodominio.com/websocket");
ws.onopen = function() { console.log("WebSocket connesso"); };
ws.onmessage = function(evt) { console.log("Ricevuto: " + evt.data); };
ws.onclose = function() { console.log("WebSocket chiuso"); };
ws.onerror = function(err) { console.log("Errore WebSocket: ", err); };

Questo registrerà gli eventi WebSocket in tempo reale, aiutandoti a debuggare i problemi di connessione.

Problemi Comuni e Soluzioni

  1. Connessione rifiutata:

    • Verifica che il tuo server WebSocket sia in esecuzione
    • Controlla che la direttiva proxy_pass punti all'indirizzo e alla porta corretti
  2. Errori del certificato SSL:

    • Assicurati che i tuoi certificati SSL siano validi e non scaduti
    • Verifica che i file dei certificati siano correttamente referenziati nella configurazione NGINX
  3. Handshake WebSocket fallito:

    • Verifica che gli header Upgrade e Connection siano impostati correttamente
    • Assicurati che proxy_http_version sia impostato su 1.1
  4. Timeout durante connessioni di lunga durata:

    • Aumenta i valori di proxy_read_timeout e proxy_send_timeout
    • Implementa un meccanismo di ping-pong nella tua applicazione WebSocket
  5. Messaggi grandi non trasmessi:

    • Aumenta client_max_body_size nella tua configurazione NGINX
    • Regola proxy_buffer_size e proxy_buffers se necessario
  6. Problemi di Cross-Origin Resource Sharing (CORS):

    • Aggiungi header per consentire CORS:
      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. Problemi di compatibilità HTTP/2:

    • Se usi HTTP/2, aggiungi proxy_set_header Connection ""; al tuo blocco location