Comment configurer NGINX comme proxy inverse pour des WebSockets sécurisés ?

Publié 8 septembre 2024

Problème : Sécuriser les connexions WebSocket avec NGINX

La mise en place d'un proxy inverse pour les connexions WebSocket peut être difficile, surtout si l'on souhaite les sécuriser. NGINX est un serveur web capable d'effectuer cette tâche, mais il faut savoir comment le configurer correctement.

Configuration de NGINX pour un proxy WebSocket sécurisé

Installation de NGINX

Pour configurer NGINX comme proxy WebSocket sécurisé, vous devez l'installer sur votre serveur. Voici les étapes :

  1. Mettez à jour votre gestionnaire de paquets :

    sudo apt update
  2. Installez NGINX :

    sudo apt install nginx
  3. Démarrez le service NGINX :

    sudo systemctl start nginx
  4. Activez NGINX pour qu'il démarre au démarrage :

    sudo systemctl enable nginx

Configuration du certificat SSL/TLS

Pour des connexions WebSocket sécurisées, vous avez besoin de certificats SSL/TLS. Voici comment les obtenir et les configurer :

  1. Installez Certbot pour obtenir des certificats Let's Encrypt gratuits :

    sudo apt install certbot python3-certbot-nginx
  2. Obtenez un certificat pour votre domaine :

    sudo certbot --nginx -d votredomaine.com
  3. Suivez les instructions pour terminer l'installation du certificat.

Configuration de NGINX pour le proxy WebSocket

Configurez maintenant NGINX pour gérer les connexions WebSocket :

  1. Ouvrez le fichier de configuration NGINX :

    sudo nano /etc/nginx/sites-available/default
  2. Ajoutez cette configuration pour activer le support WebSocket :

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

    Remplacez votredomaine.com par votre domaine et hote_backend par l'adresse de votre serveur WebSocket.

  3. Sauvegardez le fichier et quittez l'éditeur.

  4. Testez la configuration NGINX :

    sudo nginx -t
  5. Si le test est réussi, rechargez NGINX :

    sudo systemctl reload nginx

Cette configuration configure NGINX pour écouter sur le port 443 pour les connexions SSL, utiliser les certificats SSL que vous avez obtenus précédemment, et servir de proxy pour les connexions WebSocket vers votre serveur backend.

Exemple: Gestion des délais d'attente WebSocket

Pour éviter que les connexions WebSocket ne soient interrompues, vous pouvez ajouter ces directives à votre configuration NGINX :

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

Cela définit les délais de lecture et d'envoi à 1 heure (3600 secondes), ce qui aide à maintenir des connexions WebSocket de longue durée.

Mise en œuvre des paramètres du proxy WebSocket

Directives proxy_pass

Pour configurer la directive proxy_pass pour le trafic WebSocket dans NGINX :

  1. Ouvrez votre fichier de configuration NGINX :

    sudo nano /etc/nginx/sites-available/default
  2. Dans le bloc location pour les connexions WebSocket, ajoutez la directive proxy_pass :

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

    Remplacez "votre_serveur_websocket" par l'adresse de votre serveur WebSocket.

!!!astuce:"Utilisez SSL pour les connexions WebSocket" Pour sécuriser vos connexions WebSocket, utilisez SSL/TLS. Modifiez votre directive proxy_pass pour utiliser HTTPS :

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

Cela aide à protéger les données transmises entre le client et le serveur. !!!

Modifications des en-têtes

Pour configurer les en-têtes pour la communication WebSocket :

  1. Dans le même bloc location, ajoutez ces modifications d'en-têtes :

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

    Ces en-têtes aident à conserver les informations du client d'origine lors du passage par le proxy.

Gestion de la mise à niveau de la connexion

Pour gérer les mises à niveau de connexion WebSocket via NGINX :

  1. Ajoutez ces directives à votre bloc location :

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

    Les en-têtes 'Upgrade' et 'Connection' sont nécessaires pour la négociation du protocole WebSocket.

  2. Sauvegardez le fichier et quittez l'éditeur.

  3. Testez votre configuration NGINX :

    sudo nginx -t
  4. Si le test est réussi, rechargez NGINX :

    sudo systemctl reload nginx

Ces paramètres permettent à NGINX de gérer les connexions WebSocket, y compris la négociation initiale et la communication.

Optimisation de NGINX pour les performances WebSocket

Paramètres de délai d'attente

Pour gérer les connexions WebSocket de longue durée, ajustez le paramètre proxy_read_timeout dans votre configuration NGINX :

  1. Ouvrez votre fichier de configuration NGINX :

    sudo nano /etc/nginx/sites-available/default
  2. Dans votre bloc location WebSocket, ajoutez ou modifiez la directive proxy_read_timeout :

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

    Cela définit le délai de lecture à 1 heure (3600 secondes), ce qui convient à la plupart des applications WebSocket.

  3. Vous pouvez également ajouter proxy_send_timeout :

    proxy_send_timeout 3600s;

Optimisation de la taille des tampons

Pour optimiser la taille des tampons pour le trafic WebSocket :

  1. Dans le même bloc location, ajoutez ces directives :

    location /websocket/ {
       proxy_pass http://votre_serveur_websocket;
       proxy_buffering off;
       proxy_buffer_size 4k;
       proxy_buffers 4 4k;
    }
    • proxy_buffering off : Désactive la mise en tampon des réponses du serveur proxié, ce qui est souvent bon pour les connexions WebSocket.
    • proxy_buffer_size 4k : Définit la taille du tampon pour lire la première partie de la réponse du serveur proxié.
    • proxy_buffers 4 4k : Définit le nombre et la taille des tampons pour une seule connexion.
  2. Si vous attendez de gros messages, vous devrez peut-être augmenter ces valeurs :

    proxy_buffer_size 8k;
    proxy_buffers 8 8k;
  3. Sauvegardez le fichier et quittez l'éditeur.

  4. Testez votre configuration NGINX :

    sudo nginx -t
  5. Si le test est réussi, rechargez NGINX :

    sudo systemctl reload nginx

Tests et dépannage

Vérification des connexions WebSocket sécurisées

Pour tester votre configuration de proxy WebSocket :

  1. Utilisez des outils de test WebSocket en ligne :

    • Visitez websocket.org/echo.html
    • Entrez l'URL de votre WebSocket (wss://votredomaine.com/websocket)
    • Cliquez sur "Connect" et vérifiez si la connexion fonctionne
  2. Utilisez des outils en ligne de commande :

    • Installez wscat : npm install -g wscat
    • Connectez-vous à votre serveur WebSocket : wscat -c wss://votredomaine.com/websocket
    • Envoyez un message et vérifiez si vous obtenez une réponse
  3. Vérifiez les logs NGINX :

    • Consultez les logs d'erreur : sudo tail -f /var/log/nginx/error.log
    • Consultez les logs d'accès : sudo tail -f /var/log/nginx/access.log
  4. Utilisez les outils de développement du navigateur :

    • Ouvrez votre application web
    • Allez dans l'onglet Réseau
    • Filtrez les connexions WebSocket
    • Vérifiez si la connexion est établie et si les messages sont envoyés/reçus

!!!astuce:"Utilisez la console du navigateur pour déboguer WebSocket" Ouvrez la console de votre navigateur (généralement F12 ou Ctrl+Shift+I) et ajoutez le code suivant pour surveiller les événements WebSocket :

var ws = new WebSocket("wss://votredomaine.com/websocket");
ws.onopen = function() { console.log("WebSocket connecté"); };
ws.onmessage = function(evt) { console.log("Reçu : " + evt.data); };
ws.onclose = function() { console.log("WebSocket fermé"); };
ws.onerror = function(err) { console.log("Erreur WebSocket : ", err); };

Cela enregistrera les événements WebSocket en temps réel, vous aidant à déboguer les problèmes de connexion. !!!

Problèmes courants et solutions

  1. Connexion refusée :

    • Vérifiez si votre serveur WebSocket est en cours d'exécution
    • Vérifiez que la directive proxy_pass pointe vers la bonne adresse et le bon port
  2. Erreurs de certificat SSL :

    • Assurez-vous que vos certificats SSL sont valides et non expirés
    • Vérifiez que les fichiers de certificat sont correctement référencés dans la configuration NGINX
  3. Échec de la négociation WebSocket :

    • Vérifiez que les en-têtes Upgrade et Connection sont correctement définis
    • Assurez-vous que proxy_http_version est défini sur 1.1
  4. Délais d'attente lors de connexions de longue durée :

    • Augmentez les valeurs de proxy_read_timeout et proxy_send_timeout
    • Implémentez un mécanisme de ping-pong dans votre application WebSocket
  5. Grands messages non transmis :

    • Augmentez client_max_body_size dans votre configuration NGINX
    • Ajustez proxy_buffer_size et proxy_buffers si nécessaire
  6. Problèmes de partage des ressources entre origines (CORS) :

    • Ajoutez des en-têtes pour autoriser 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. Problèmes de compatibilité HTTP/2 :

    • Si vous utilisez HTTP/2, ajoutez proxy_set_header Connection ""; à votre bloc location