es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo hacer un proxy de solicitud websocket a un backend TCP usando nginx.

Quería configurar nginx para que actúe como proxy de datos de websocket desde un cliente web de websocket hasta un servidor TCP utilizando nginx.

Esto se debe a que un cliente web no puede conectarse directamente a un servidor TCP. Describa lo que ha intentado.

Intenté usar el módulo yaoweibin/nginxtcpproxymodule. Se puede encontrar aquí: https://github.com/yaoweibin/nginxtcpproxymodule.

He utilizado esta configuración de nginx:

    tcp {
        upstream cluster {
            # simple round-robin
            server localhost:8889;
            server localhost:8889;
            check interval=3000 rise=2 fall=5 timeout=50000;
        }
    }

    upstream ws {
        server 127.0.0.1:85;
    }

    server {
        listen 8888 ;
        proxy_pass cluster;
    }
}

http {

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

    upstream ws_backend {
      server localhost:8010;
    }

    upstream tcp_backend {
      server localhost:8888;
    }

    server {
            listen 85;

            location / {
                proxy_pass http://tcp_backend;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
            }

            location /status {
                tcp_check_status;
            }

    }
}

El comportamiento observado:
– cuando el cliente de websocket intenta conectarse, el servidor TCP recibe datos:

DATA 127.0.0.1: GET / HTTP/1.1
Upgrade: websocket
Connection: upgrade
Host: tcp_backend
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dXQD1uqFI498I58eRmDFAw==
Sec-WebSocket-Protocol: echo-protocol

  • pero el cliente de websocket después de un tiempo muerto genera un error de conexión:

Connect Error: Error: socket hang up

¿Me pueden ayudar por favor si tienen una solución alternativa (usando lua/nginx) o algo basado en nginx?

Gracias.

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Sí, puedo sugerir una solución alternativa utilizando nginx y Lua. Puedes utilizar el módulo de stream de nginx junto con Lua para redirigir los datos de la websocket a un servidor TCP. Aquí hay una configuración de ejemplo:

    stream {
        lua_package_path "/usr/local/openresty/lualib/?.lua;;";
    
        init_by_lua_block {
            local sock = ngx.socket.tcp()
            local ok, err = sock:connect("127.0.0.1", 8889)
            if not ok then
                ngx.log(ngx.ERR, "falló la conexión con el servidor TCP: ", err)
            else
                ngx.ctx.tcp_sock = sock
            end
        }
    
        server {
            listen 8888;
    
            content_by_lua_block {
                local tcp_sock = ngx.ctx.tcp_sock
                if not tcp_sock then
                    ngx.log(ngx.ERR, "socket TCP no inicializado")
                    ngx.exit(ngx.ERROR)
                end
    
                ngx.req.read_body()
                local data = ngx.req.raw_header() .. ngx.req.get_body_data()
                local bytes, err = tcp_sock:send(data)
                if not bytes then
                    ngx.log(ngx.ERR, "falló el envío de datos al servidor TCP: ", err)
                    ngx.exit(ngx.ERROR)
                end
    
                local response, err = tcp_sock:receive()
                if not response then
                    ngx.log(ngx.ERR, "falló la recepción de la respuesta del servidor TCP: ", err)
                    ngx.exit(ngx.ERROR)
                end
    
                ngx.print(response)
            }
    
            preread_by_lua_block {
                -- habilitar protocolo proxy
                local client_ip, client_port = ngx.var.proxy_protocol_addr, ngx.var.proxy_protocol_port
                if client_ip and client_port then
                    ngx.var.upstream_addr = "127.0.0.1:85"
                    return
                end
    
                -- habilitar websocket
                ngx.req.set_header("Upgrade", "websocket")
                ngx.req.set_header("Connection", "upgrade")
                ngx.req.set_header("Sec-WebSocket-Version", "13")
                ngx.req.set_header("Sec-WebSocket-Key", "") -- generar una clave aleatoria aquí
                ngx.var.upstream_addr = "127.0.0.1:85"
            }
        }
    }
    
    http {
        upstream ws_backend {
            server localhost:8010;
        }
    
        server {
            listen 85;
    
            location / {
                proxy_pass http://ws_backend;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection $connection_upgrade;
            }
    
            location /status {
                nginx_tcp_proxy_pass;
            }
        }
    }
    

    En esta configuración, utilizamos el módulo de stream para redirigir el tráfico TCP desde el cliente de la websocket al servidor TCP, y utilizamos Lua para leer y escribir el tráfico TCP. También utilizamos la directiva preread_by_lua para habilitar el protocolo proxy o la websocket, según el tráfico que ingresa.

    Espero que esto sea de ayuda. Déjame saber si tienes alguna pregunta o necesitas más ayuda.

Comments are closed.