Como configurar o NGINX como um proxy reverso para WebSockets seguros?

Publicado 8 de setembro de 2024

Problema: Protegendo conexões WebSocket com NGINX

Configurar um proxy reverso para conexões WebSocket pode ser difícil, especialmente quando você quer mantê-las seguras. O NGINX é um servidor web que pode fazer esse trabalho, mas você precisa saber como configurá-lo corretamente.

Configurando o NGINX para proxy WebSocket seguro

Instalando o NGINX

Para configurar o NGINX como proxy WebSocket seguro, você precisa instalá-lo no seu servidor. Siga estes passos:

  1. Atualize seu gerenciador de pacotes:

    sudo apt update
  2. Instale o NGINX:

    sudo apt install nginx
  3. Inicie o serviço NGINX:

    sudo systemctl start nginx
  4. Habilite o NGINX para iniciar na inicialização:

    sudo systemctl enable nginx

Configuração do certificado SSL/TLS

Para conexões WebSocket seguras, você precisa de certificados SSL/TLS. Veja como obtê-los e configurá-los:

  1. Instale o Certbot para certificados gratuitos Let's Encrypt:

    sudo apt install certbot python3-certbot-nginx
  2. Obtenha um certificado para seu domínio:

    sudo certbot --nginx -d seudominio.com
  3. Siga as instruções para concluir a instalação do certificado.

Configuração do NGINX para proxy WebSocket

Agora, configure o NGINX para fazer proxy de conexões WebSocket:

  1. Abra o arquivo de configuração do NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. Adicione esta configuração para habilitar o suporte a WebSocket:

    server {
       listen 443 ssl;
       server_name seudominio.com;
    
       ssl_certificate /etc/letsencrypt/live/seudominio.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/seudominio.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";
       }
    }

    Substitua seudominio.com pelo seu domínio e servidor_backend pelo endereço do seu servidor WebSocket.

  3. Salve o arquivo e saia do editor.

  4. Teste a configuração do NGINX:

    sudo nginx -t
  5. Se o teste passar, recarregue o NGINX:

    sudo systemctl reload nginx

Esta configuração define o NGINX para ouvir na porta 443 para conexões SSL, usar os certificados SSL obtidos anteriormente e fazer proxy de conexões WebSocket para seu servidor backend.

Exemplo: Lidando com timeouts de WebSocket

Para evitar que as conexões WebSocket expirem, você pode adicionar estas diretivas à sua configuração 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;
}

Isso define os timeouts de leitura e envio para 1 hora (3600 segundos), o que ajuda a manter conexões WebSocket de longa duração.

Implementando configurações de proxy WebSocket

Diretivas proxy_pass

Para configurar a diretiva proxy_pass para tráfego WebSocket no NGINX:

  1. Abra seu arquivo de configuração NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. No bloco de localização para conexões WebSocket, adicione a diretiva proxy_pass:

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

    Substitua "seu_servidor_websocket" pelo endereço do seu servidor WebSocket.

Dica: Use SSL para conexões WebSocket

Para proteger suas conexões WebSocket, use SSL/TLS. Modifique sua diretiva proxy_pass para usar HTTPS:

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

Isso ajuda a proteger os dados transmitidos entre o cliente e o servidor.

Modificações de cabeçalho

Para configurar os cabeçalhos para comunicação WebSocket:

  1. No mesmo bloco de localização, adicione estas modificações de cabeçalho:

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

    Esses cabeçalhos ajudam a manter as informações originais do cliente ao passar pelo proxy.

Tratamento de upgrade de conexão

Para gerenciar upgrades de conexão WebSocket através do NGINX:

  1. Adicione estas diretivas ao seu bloco de localização:

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

    Os cabeçalhos 'Upgrade' e 'Connection' são necessários para o handshake do protocolo WebSocket.

  2. Salve o arquivo e saia do editor.

  3. Teste sua configuração NGINX:

    sudo nginx -t
  4. Se o teste for bem-sucedido, recarregue o NGINX:

    sudo systemctl reload nginx

Essas configurações permitem que o NGINX trate conexões WebSocket, incluindo o handshake inicial e a comunicação.

Ajustando o NGINX para desempenho ideal de WebSocket

Configurações de timeout

Para lidar com conexões WebSocket de longa duração, ajuste a configuração proxy_read_timeout no seu arquivo de configuração NGINX:

  1. Abra seu arquivo de configuração NGINX:

    sudo nano /etc/nginx/sites-available/default
  2. No seu bloco de localização WebSocket, adicione ou modifique a diretiva proxy_read_timeout:

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

    Isso define o timeout de leitura para 1 hora (3600 segundos), o que é bom para a maioria das aplicações WebSocket.

  3. Você também pode adicionar proxy_send_timeout:

    proxy_send_timeout 3600s;

Otimização do tamanho do buffer

Para otimizar os tamanhos de buffer para tráfego WebSocket:

  1. No mesmo bloco de localização, adicione estas diretivas:

    location /websocket/ {
       proxy_pass http://seu_servidor_websocket;
       proxy_buffering off;
       proxy_buffer_size 4k;
       proxy_buffers 4 4k;
    }
    • proxy_buffering off: Isso desativa o buffering de respostas do servidor proxy, o que geralmente é bom para conexões WebSocket.
    • proxy_buffer_size 4k: Isso define o tamanho do buffer para ler a primeira parte da resposta do servidor proxy.
    • proxy_buffers 4 4k: Isso define o número e o tamanho dos buffers para uma única conexão.
  2. Se você espera mensagens grandes, pode ser necessário aumentar esses valores:

    proxy_buffer_size 8k;
    proxy_buffers 8 8k;
  3. Salve o arquivo e saia do editor.

  4. Teste sua configuração NGINX:

    sudo nginx -t
  5. Se o teste passar, recarregue o NGINX:

    sudo systemctl reload nginx

Testando e solucionando problemas

Verificando conexões WebSocket seguras

Para testar sua configuração de proxy WebSocket:

  1. Use ferramentas online de teste de WebSocket:

    • Visite websocket.org/echo.html
    • Digite sua URL WebSocket (wss://seudominio.com/websocket)
    • Clique em "Connect" e verifique se a conexão funciona
  2. Use ferramentas de linha de comando:

    • Instale o wscat: npm install -g wscat
    • Conecte-se ao seu servidor WebSocket: wscat -c wss://seudominio.com/websocket
    • Envie uma mensagem e verifique se recebe uma resposta
  3. Verifique os logs do NGINX:

    • Veja os logs de erro: sudo tail -f /var/log/nginx/error.log
    • Veja os logs de acesso: sudo tail -f /var/log/nginx/access.log
  4. Use as ferramentas de desenvolvedor do navegador:

    • Abra sua aplicação web
    • Vá para a aba Network
    • Filtre por conexões WebSocket
    • Verifique se a conexão é estabelecida e se as mensagens são enviadas/recebidas

Dica: Use o Console do Navegador para Depuração de WebSocket

Abra o console do seu navegador (geralmente F12 ou Ctrl+Shift+I) e adicione o seguinte código para monitorar eventos WebSocket:

var ws = new WebSocket("wss://seudominio.com/websocket");
ws.onopen = function() { console.log("WebSocket conectado"); };
ws.onmessage = function(evt) { console.log("Recebido: " + evt.data); };
ws.onclose = function() { console.log("WebSocket fechado"); };
ws.onerror = function(err) { console.log("Erro WebSocket: ", err); };

Isso registrará eventos WebSocket em tempo real, ajudando você a depurar problemas de conexão.

Problemas comuns e soluções

  1. Conexão recusada:

    • Verifique se seu servidor WebSocket está rodando
    • Confirme se a diretiva proxy_pass aponta para o endereço e porta corretos
  2. Erros de certificado SSL:

    • Certifique-se de que seus certificados SSL são válidos e não estão expirados
    • Verifique se os arquivos de certificado estão corretamente referenciados na configuração do NGINX
  3. Falha no handshake WebSocket:

    • Verifique se os cabeçalhos Upgrade e Connection estão configurados corretamente
    • Certifique-se de que proxy_http_version está definido como 1.1
  4. Timeouts durante conexões de longa duração:

    • Aumente os valores de proxy_read_timeout e proxy_send_timeout
    • Implemente um mecanismo de ping-pong em sua aplicação WebSocket
  5. Mensagens grandes não sendo transmitidas:

    • Aumente client_max_body_size na sua configuração NGINX
    • Ajuste proxy_buffer_size e proxy_buffers se necessário
  6. Problemas de Compartilhamento de Recursos de Origem Cruzada (CORS):

    • Adicione cabeçalhos 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 compatibilidade com HTTP/2:

    • Se estiver usando HTTP/2, adicione proxy_set_header Connection ""; ao seu bloco de localização