NGINX para reverter websockets de proxy E ativar SSL (wss: //)?

136

Estou tão perdido e novo em criar o NGINX por conta própria, mas quero poder habilitar soquetes da web seguros sem ter uma camada adicional.

Não quero habilitar o SSL no servidor websocket, mas quero usar o NGINX para adicionar uma camada SSL à coisa toda.

Toda página da web diz que não posso fazer isso, mas sei que posso! Obrigado a quem (eu) possa me mostrar como!

crockpotveggies
fonte

Respostas:

185

Apenas para observar que o nginx agora tem suporte para Websockets na versão 1.3.13. Exemplo de uso:

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 86400;

}

Você também pode verificar o changelog nginx e a documentação de proxy do WebSocket .

Tarântula
fonte
Ele tem os mesmos problemas de tempo limite expressos acima;)
3rdEden 04/04
5
@ 3rdEden: Por questões de tempo limite, proxy_read_timeoutfunciona, editei a resposta.
precisa saber é o seguinte
2
Onde devo colocar essa configuração e o que é backend_host?
Aysennoussi
3
@Sekai: Uma locationdiretiva é colocada dentro de uma serverou outra locationdiretiva (consulte a documentação do local ). backend_hosté um upstream(consulte os documentos upstream ) - um ou um grupo de servidores aos quais você fará proxy.
Radko Dinev
1
E esse problema de tempo limite? Temos realmente que definir um número muito grande para evitá-lo? Não existe agora nenhuma solução mais elegante?
Mohammed Noureldin
54

Não tenha medo, porque um corajoso grupo de programadores de operações resolveu a situação com uma nova marca nginx_tcp_proxy_module

Escrito em agosto de 2012, por isso, se você é do futuro, deve fazer sua lição de casa.

Pré-requisitos

Supõe que você esteja usando o CentOS:

  • Remova a instância atual do NGINX (sugira usar o servidor de desenvolvimento para isso)
  • Se possível, salve seus arquivos de configuração antigos do NGINX para poder reutilizá-los (isso inclui seu init.d/nginxscript)
  • yum install pcre pcre-devel openssl openssl-devel e quaisquer outras bibliotecas necessárias para criar o NGINX
  • Obtenha o nginx_tcp_proxy_module no GitHub aqui https://github.com/yaoweibin/nginx_tcp_proxy_module e lembre-se da pasta onde você a colocou (verifique se não está compactado)

Crie seu novo NGINX

Novamente, assume o CentOS:

  • cd /usr/local/
  • wget 'http://nginx.org/download/nginx-1.2.1.tar.gz'
  • tar -xzvf nginx-1.2.1.tar.gz
  • cd nginx-1.2.1/
  • patch -p1 < /path/to/nginx_tcp_proxy_module/tcp.patch
  • ./configure --add-module=/path/to/nginx_tcp_proxy_module --with-http_ssl_module (você pode adicionar mais módulos, se precisar)
  • make
  • make install

Opcional:

  • sudo /sbin/chkconfig nginx on

Configurar o Nginx

Lembre-se de copiar primeiro os arquivos de configuração antigos, se desejar reutilizá-los.

Importante: você precisará criar uma tcp {}diretiva no nível mais alto da sua conf. Verifique se ele não está dentro da sua http {}diretiva.

A configuração de exemplo abaixo mostra um servidor websocket upstream único e dois proxies para SSL e Não SSL.

tcp {
    upstream websockets {
        ## webbit websocket server in background
        server 127.0.0.1:5501;
        
        ## server 127.0.0.1:5502; ## add another server if you like!

        check interval=3000 rise=2 fall=5 timeout=1000;
    }   

    server {
        server_name _;
        listen 7070;

        timeout 43200000;
        websocket_connect_timeout 43200000;
        proxy_connect_timeout 43200000;

        so_keepalive on;
        tcp_nodelay on;

        websocket_pass websockets;
        websocket_buffer 1k;
    }

    server {
        server_name _;
        listen 7080;

        ssl on;
        ssl_certificate      /path/to/cert.pem;
        ssl_certificate_key  /path/to/key.key;

        timeout 43200000;
        websocket_connect_timeout 43200000;
        proxy_connect_timeout 43200000;

        so_keepalive on;
        tcp_nodelay on;

        websocket_pass websockets;
        websocket_buffer 1k;
    }
}
crockpotveggies
fonte
5
Isso foi bastante útil, mas eu ainda estava recebendo intervalos em 60 segundos. Eu consegui corrigir isso definindo o seguinte: timeout 43200000; websocket_connect_timeout 43200000; websocket_read_timeout 43200000; websocket_send_timeout 43200000; proxy_connect_timeout 43200000; proxy_read_timeout 43200000; proxy_send_timeout 43200000;
jbg
2
Obrigado por compartilhar isso! Mais tarde, percebi que estava tendo problemas semelhantes e, coincidentemente, o próprio yaoweibin também respondeu ao meu problema do GitHub com um link para o seu comentário na edição nº 28. Mundo pequeno ...
crockpotveggies
1
Eu queria servir websockets na mesma porta http e somente após a autenticação do navegador. Parece que isso não pode lidar com websockets na mesma porta. Como as pessoas lidam com isso?
uroc
1
Serão necessárias algumas modificações no software para detectar o protocolo recebido. Como os websockets realmente iniciam como um handshake HTTP (um nível de software superior ao TCP), você precisa ajustar seu aplicativo para lidar com o tráfego TCP e HTTP. Ainda não posso recomendar uma maneira de fazer isso.
precisa
2
Caso outras pessoas de 2018 cheguem aqui, essas diretrizes não funcionam mais. Acesse nginx.org/en/docs/http/websocket.html para obter instruções recentes ou consulte a resposta de Harlan T Wood abaixo.
GaryO
37

Isso funcionou para mim:

location / {
    # redirect all HTTP traffic to localhost:8080
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

- emprestado de: https://github.com/nicokaiser/nginx-websocket-proxy/blob/df67cd92f71bfcb513b343beaa89cb33ab09fb05/simple-wss.conf

Harlan T Wood
fonte
3
Eu tive problemas para fazer com que os soquetes da Web do TeamCity funcionassem por trás do meu proxy reverso. Você # WebSocket supportcortou fez isso por mim. Eu estava anteriormente tentando encaminhar a porta 400, obras no entanto WSS mais de 443. leitores FYI futuras :)
Mario Tacke
Você já descobriu a solução? Desde que eu tive que também enfrentou um problema semelhante stackoverflow.com/q/53411060/7713811
Nɪsʜᴀɴᴛʜ
Eu gosto desta resposta da melhor maneira, pois muitas pessoas (como você) usam / para websockets e HTTP2 comum.
Mikemaccana 27/03/19
@ Qualquer um que seria o chamado Javascript?
Andrew Simpson
17

para .net core 2.0 Nginx com SSL

location / {
    # redirect all HTTP traffic to localhost:8080
    proxy_pass http://localhost:8080;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    # WebSocket support
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;
}

Isso funcionou para mim

Altair CA
fonte
qual é o código c # Atualmente, tenho isso no windows / iis _server = new WebSocketServer ("wss: //0.0.0.0: 8200 / MessageRelayer") {Certificate = new X509Certificate2 (PfxFileName, SslPassword), RestartAfterListenError = true};
Andrew Simpson
Estou usando SignalR
Altair CA
Esta foi a única solução que funcionou para mim. Obrigado!
m-ketan 16/03
8

Para mim, tudo se resumia à proxy_passconfiguração do local. Eu precisava mudar para usar o protocolo HTTPS e ter um certificado SSL válido configurado no servidor do nó. Dessa forma, quando eu apresento um servidor de nó externo, só preciso alterar o IP e tudo o mais permanece a mesma configuração.

Espero que isso ajude alguém ao longo do caminho ... Fiquei olhando o problema o tempo todo ... suspiro ...

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
upstream nodeserver {
        server 127.0.0.1:8080;
}
server {
        listen 443 default_server ssl http2;
        listen [::]:443 default_server ssl http2 ipv6only=on;
        server_name mysite.com;
        ssl_certificate ssl/site.crt;
        ssl_certificate_key ssl/site.key;
        location /websocket { #replace /websocket with the path required by your application
                proxy_pass https://nodeserver;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
                proxy_http_version 1.1;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_intercept_errors on;
                proxy_redirect off;
                proxy_cache_bypass $http_upgrade;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-NginX-Proxy true;
                proxy_ssl_session_reuse off;
            }
}
CyberDigital
fonte
Eu tentei localtion /horizon, mas não está funcionando. Somente localtion /ou location /websockifyfunciona. Não sei por que ... #
28718 njuguoyi
6

Um artigo bom e conciso de Pankaj Malhotra discute como fazer isso com o NGINX e está disponível aqui .

A configuração básica do NGINX é reproduzida abaixo:

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream appserver {
    server 192.168.100.10:9222; # appserver_ip:ws_port
}

server {
    listen 8888; // client_wss_port

    ssl on;
    ssl_certificate /path/to/crt;
    ssl_certificate_key /path/to/key;


    location / {
        proxy_pass http://appserver;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
    }
}
btiernay
fonte
1
As versões modernas do NGINX também abordam os problemas de tempo limite?
Crockpotveggies
2

Usando nginx / 1.14.0

Eu tenho um servidor websocket em execução na porta 8097 e os usuários se conectam ao wss na porta 8098, o nginx apenas descriptografa o conteúdo e o encaminha para o servidor websocket

Então, eu tenho esse arquivo de configuração (no meu caso /etc/nginx/conf.d/default.conf)

server {
    listen   8098;
        ssl on;
        ssl_certificate      /etc/ssl/certs/combined.pem;
        ssl_certificate_key  /root/domain.key;
    location / {

        proxy_pass http://hostname:8097;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 86400;

    }
}
john Smith
fonte