¿Cómo configurar NGINX como un proxy inverso para WebSockets seguros?

Publicado 8 de septiembre de 2024

Problema: Asegurar conexiones WebSocket con NGINX

Configurar un proxy inverso para conexiones WebSocket puede ser complicado, especialmente si se quiere mantener seguro. NGINX es un servidor web que puede realizar esta tarea, pero es necesario saber cómo configurarlo correctamente.

Configuración de NGINX para proxy WebSocket seguro

Instalación de NGINX

Para configurar NGINX como proxy WebSocket seguro, necesitas instalarlo en tu servidor. Sigue estos pasos:

  1. Actualiza tu gestor de paquetes:

    sudo apt update
  2. Instala NGINX:

    sudo apt install nginx
  3. Inicia el servicio NGINX:

    sudo systemctl start nginx
  4. Habilita NGINX para que se inicie al arrancar:

    sudo systemctl enable nginx

Configuración del certificado SSL/TLS

Para conexiones WebSocket seguras, necesitas certificados SSL/TLS. Así es cómo obtenerlos y configurarlos:

  1. Instala Certbot para obtener certificados gratuitos de Let's Encrypt:

    sudo apt install certbot python3-certbot-nginx
  2. Obtén un certificado para tu dominio:

    sudo certbot --nginx -d tudominio.com
  3. Sigue las indicaciones para completar la instalación del certificado.

Configuración de NGINX para proxy WebSocket

Ahora, configura NGINX para hacer proxy de conexiones WebSocket:

  1. Abre el archivo de configuración de NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. Añade esta configuración para habilitar el soporte de WebSocket:

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

    Reemplaza tudominio.com con tu dominio y servidor_backend con la dirección de tu servidor WebSocket.

  3. Guarda el archivo y sal del editor.

  4. Comprueba la configuración de NGINX:

    sudo nginx -t
  5. Si la prueba pasa, recarga NGINX:

    sudo systemctl reload nginx

Esta configuración prepara NGINX para escuchar en el puerto 443 para conexiones SSL, usar los certificados SSL que obtuviste anteriormente y hacer proxy de conexiones WebSocket a tu servidor backend.

Ejemplo: Manejo de tiempos de espera de WebSocket

Para evitar que las conexiones WebSocket se cierren por tiempo de espera, puedes añadir estas directivas a tu configuración de NGINX:

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

Esto establece los tiempos de espera de lectura y envío a 1 hora (3600 segundos), lo que ayuda a mantener conexiones WebSocket de larga duración.

Implementación de configuraciones de proxy WebSocket

Directivas proxy_pass

Para configurar la directiva proxy_pass para el tráfico WebSocket en NGINX:

  1. Abre tu archivo de configuración de NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. En el bloque de ubicación para conexiones WebSocket, añade la directiva proxy_pass:

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

    Reemplaza "tu_servidor_websocket" con la dirección de tu servidor WebSocket.

Consejo: Usa SSL para conexiones WebSocket

Para asegurar tus conexiones WebSocket, usa SSL/TLS. Modifica tu directiva proxy_pass para usar HTTPS:

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

Esto ayuda a proteger los datos transmitidos entre el cliente y el servidor.

Modificaciones de encabezados

Para configurar los encabezados para la comunicación WebSocket:

  1. En el mismo bloque de ubicación, añade estas modificaciones de encabezados:

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

    Estos encabezados ayudan a mantener la información del cliente original al pasar por el proxy.

Manejo de actualización de conexión

Para gestionar las actualizaciones de conexión WebSocket a través de NGINX:

  1. Añade estas directivas a tu bloque de ubicación:

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

    Los encabezados 'Upgrade' y 'Connection' son necesarios para el protocolo de enlace WebSocket.

  2. Guarda el archivo y sal del editor.

  3. Comprueba tu configuración de NGINX:

    sudo nginx -t
  4. Si la prueba es exitosa, recarga NGINX:

    sudo systemctl reload nginx

Estas configuraciones permiten a NGINX manejar conexiones WebSocket, incluyendo el enlace inicial y la comunicación.

Ajuste fino de NGINX para un rendimiento óptimo de WebSocket

Configuración de tiempos de espera

Para manejar conexiones WebSocket de larga duración, ajusta la configuración proxy_read_timeout en tu configuración de NGINX:

  1. Abre tu archivo de configuración de NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. En tu bloque de ubicación WebSocket, añade o modifica la directiva proxy_read_timeout:

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

    Esto establece el tiempo de espera de lectura a 1 hora (3600 segundos), lo cual es adecuado para la mayoría de las aplicaciones WebSocket.

  3. También puedes añadir proxy_send_timeout:

    proxy_send_timeout 3600s;

Optimización del tamaño del búfer

Para optimizar los tamaños de búfer para el tráfico WebSocket:

  1. En el mismo bloque de ubicación, añade estas directivas:

    location /websocket/ {
       proxy_pass http://tu_servidor_websocket;
       proxy_buffering off;
       proxy_buffer_size 4k;
       proxy_buffers 4 4k;
    }
    • proxy_buffering off: Esto desactiva el almacenamiento en búfer de las respuestas del servidor proxy, lo cual suele ser bueno para conexiones WebSocket.
    • proxy_buffer_size 4k: Esto establece el tamaño del búfer para leer la primera parte de la respuesta del servidor proxy.
    • proxy_buffers 4 4k: Esto establece el número y tamaño de los búferes para una sola conexión.
  2. Si esperas mensajes grandes, es posible que necesites aumentar estos valores:

    proxy_buffer_size 8k;
    proxy_buffers 8 8k;
  3. Guarda el archivo y sal del editor.

  4. Comprueba tu configuración de NGINX:

    sudo nginx -t
  5. Si la prueba pasa, recarga NGINX:

    sudo systemctl reload nginx

Pruebas y solución de problemas

Verificación de conexiones WebSocket seguras

Para probar tu configuración de proxy WebSocket:

  1. Usa herramientas de prueba de WebSocket en línea:

    • Visita websocket.org/echo.html
    • Introduce tu URL de WebSocket (wss://tudominio.com/websocket)
    • Haz clic en "Connect" y comprueba si la conexión funciona
  2. Usa herramientas de línea de comandos:

    • Instala wscat: npm install -g wscat
    • Conéctate a tu servidor WebSocket: wscat -c wss://tudominio.com/websocket
    • Envía un mensaje y comprueba si recibes una respuesta
  3. Revisa los registros de NGINX:

    • Ver registros de errores: sudo tail -f /var/log/nginx/error.log
    • Ver registros de acceso: sudo tail -f /var/log/nginx/access.log
  4. Usa las herramientas de desarrollador del navegador:

    • Abre tu aplicación web
    • Ve a la pestaña Network
    • Filtra las conexiones WebSocket
    • Comprueba si la conexión se establece y los mensajes se envían/reciben

Consejo: Usa la consola del navegador para depurar WebSocket

Abre la consola de tu navegador (normalmente F12 o Ctrl+Shift+I) y añade el siguiente código para monitorizar eventos WebSocket:

var ws = new WebSocket("wss://tudominio.com/websocket");
ws.onopen = function() { console.log("WebSocket conectado"); };
ws.onmessage = function(evt) { console.log("Recibido: " + evt.data); };
ws.onclose = function() { console.log("WebSocket cerrado"); };
ws.onerror = function(err) { console.log("Error de WebSocket: ", err); };

Esto registrará los eventos WebSocket en tiempo real, ayudándote a depurar problemas de conexión.

Problemas comunes y soluciones

  1. Conexión rechazada:

    • Comprueba si tu servidor WebSocket está en ejecución
    • Verifica que la directiva proxy_pass apunta a la dirección y puerto correctos
  2. Errores de certificado SSL:

    • Asegúrate de que tus certificados SSL sean válidos y no hayan expirado
    • Comprueba que los archivos de certificados estén correctamente referenciados en la configuración de NGINX
  3. Fallo en el protocolo de enlace WebSocket:

    • Verifica que los encabezados Upgrade y Connection estén configurados correctamente
    • Asegúrate de que proxy_http_version esté configurado como 1.1
  4. Tiempos de espera durante conexiones de larga duración:

    • Aumenta los valores de proxy_read_timeout y proxy_send_timeout
    • Implementa un mecanismo de ping-pong en tu aplicación WebSocket
  5. Mensajes grandes que no se transmiten:

    • Aumenta client_max_body_size en tu configuración de NGINX
    • Ajusta proxy_buffer_size y proxy_buffers si es necesario
  6. Problemas de Compartición de Recursos de Origen Cruzado (CORS):

    • Añade encabezados para permitir 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. Problemas de compatibilidad con HTTP/2:

    • Si usas HTTP/2, añade proxy_set_header Connection ""; a tu bloque de ubicación