Saltar a contenido

stream-lua: Soporte de scripting Lua para streams de NGINX

Instalación

Puedes instalar este módulo en cualquier distribución basada en RHEL, incluyendo, pero no limitado a:

  • RedHat Enterprise Linux 7, 8, 9 y 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 y Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install nginx-module-stream-lua
yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install nginx-module-stream-lua

Habilita el módulo añadiendo lo siguiente en la parte superior de /etc/nginx/nginx.conf:

load_module modules/ngx_stream_lua_module.so;

Este documento describe nginx-module-stream-lua v0.0.18 lanzado el 27 de marzo de 2026.


Sinopsis

events {
    worker_connections 1024;
}

stream {
    # define un servidor TCP escuchando en el puerto 1234:
    server {
        listen 1234;

        content_by_lua_block {
            ngx.say("¡Hola, Lua!")
        }
    }
}

Configurado como un servidor TCP SSL:

stream {
    server {
        listen 4343 ssl;

        ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
        ssl_ciphers         AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
        ssl_certificate     /path/to/cert.pem;
        ssl_certificate_key /path/to/cert.key;
        ssl_session_cache   shared:SSL:10m;
        ssl_session_timeout 10m;

        content_by_lua_block {
            local sock = assert(ngx.req.socket(true))
            local data = sock:receive()  -- lee una línea del downstream
            if data == "thunder!" then
                ngx.say("flash!")  -- salida de datos
            else
                ngx.say("boom!")
            end
            ngx.say("el fin...")
        }
    }
}

También se admite la escucha en un socket de dominio UNIX:

stream {
    server {
        listen unix:/tmp/nginx.sock;

        content_by_lua_block {
            ngx.say("¿Qué tal?")
            ngx.flush(true)  -- vacía cualquier salida pendiente y espera
            ngx.sleep(3)  -- durmiendo por 3 seg
            ngx.say("Adiós...")
        }
    }
}

Descripción

Este es un puerto del ngx_http_lua_module al sub-sistema "stream" de Nginx para soportar clientes de stream/TCP genéricos.

Las APIs de Lua disponibles y las directivas de Nginx permanecen iguales a las del módulo ngx_http_lua.

Directivas

Las siguientes directivas se han portado directamente desde ngx_http_lua. Por favor revisa la documentación de ngx_http_lua para más detalles sobre su uso y comportamiento.

La directiva send_timeout en el subsistema "http" de Nginx no está presente en el subsistema "stream". Por lo tanto, ngx_stream_lua_module utiliza la directiva lua_socket_send_timeout para este propósito.

Nota: la directiva de cierre persistente que existía en versiones anteriores de stream_lua_nginx_module ha sido eliminada y ahora se puede simular con el API tcpsock:shutdown recién añadido si es necesario.

preread_by_lua_block

sintaxis: preread_by_lua_block { lua-script }

contexto: stream, server

fase: preread

Actúa como un manejador de fase preread y ejecuta la cadena de código Lua especificada en lua-script para cada conexión (o paquete en modo datagrama). El código Lua puede hacer llamadas a la API y se ejecuta como una nueva coroutine generada en un entorno global independiente (es decir, un sandbox).

Es posible adquirir el socket de solicitud en bruto utilizando ngx.req.socket y recibir datos del cliente o enviar datos al cliente. Sin embargo, ten en cuenta que llamar al método receive() del socket de solicitud consumirá los datos del búfer y esos datos consumidos no serán visibles para los manejadores más adelante en la cadena.

El código preread_by_lua_block siempre se ejecutará al final de la fase de procesamiento preread a menos que preread_by_lua_no_postpone esté activado.

Esta directiva se introdujo por primera vez en la versión v0.0.3.

Volver a la tabla de contenido

preread_by_lua_file

sintaxis: preread_by_lua_file <path-to-lua-script-file>

contexto: stream, server

fase: preread

Equivalente a preread_by_lua_block, excepto que el archivo especificado por <path-to-lua-script-file> contiene el código Lua o bytecode de LuaJIT a ser ejecutado.

Se pueden usar variables de Nginx en la cadena <path-to-lua-script-file> para proporcionar flexibilidad. Sin embargo, esto conlleva algunos riesgos y no se recomienda normalmente.

Cuando se proporciona una ruta relativa como foo/bar.lua, se convertirá en la ruta absoluta relativa a la ruta de server prefix determinada por la opción de línea de comandos -p PATH dada al iniciar el servidor Nginx.

Cuando la caché de código Lua está activada (por defecto), el código del usuario se carga una vez en la primera conexión y se almacena en caché. La configuración de Nginx debe recargarse cada vez que se modifica el archivo fuente de Lua. La caché de código Lua se puede desactivar temporalmente durante el desarrollo cambiando lua_code_cache a off en nginx.conf para evitar tener que recargar Nginx.

Esta directiva se introdujo por primera vez en la versión v0.0.3.

Volver a la tabla de contenido

log_by_lua_block

sintaxis: log_by_lua_block { lua-script }

contexto: stream, server

fase: log

Ejecuta el código fuente Lua especificado como <lua-script> durante la fase de procesamiento de log de la solicitud. Esto no reemplaza los registros de acceso actuales, sino que se ejecuta antes.

Las APIs que generan salida como ngx.req.socket, ngx.socket.*, ngx.sleep, o ngx.say no están disponibles en esta fase.

Esta directiva se introdujo por primera vez en la versión v0.0.3.

Volver a la tabla de contenido

log_by_lua_file

sintaxis: log_by_lua_file <path-to-lua-script-file>

contexto: stream, server

fase: log

Equivalente a log_by_lua_block, excepto que el archivo especificado por <path-to-lua-script-file> contiene el código Lua o bytecode de LuaJIT a ser ejecutado.

Se pueden usar variables de Nginx en la cadena <path-to-lua-script-file> para proporcionar flexibilidad. Sin embargo, esto conlleva algunos riesgos y no se recomienda normalmente.

Cuando se proporciona una ruta relativa como foo/bar.lua, se convertirá en la ruta absoluta relativa a la ruta de server prefix determinada por la opción de línea de comandos -p PATH dada al iniciar el servidor Nginx.

Cuando la caché de código Lua está activada (por defecto), el código del usuario se carga una vez en la primera conexión y se almacena en caché. La configuración de Nginx debe recargarse cada vez que se modifica el archivo fuente de Lua. La caché de código Lua se puede desactivar temporalmente durante el desarrollo cambiando lua_code_cache a off en nginx.conf para evitar tener que recargar Nginx.

Esta directiva se introdujo por primera vez en la versión v0.0.3.

Volver a la tabla de contenido

lua_add_variable

sintaxis: lua_add_variable $var

contexto: stream

Añade la variable $var al subsistema "stream" y la hace modificable. Si $var ya existe, esta directiva no hará nada.

Por defecto, las variables añadidas usando esta directiva se consideran "no encontradas" y leerlas usando ngx.var devolverá nil. Sin embargo, pueden ser reasignadas a través de la API ngx.var.VARIABLE en cualquier momento.

Esta directiva se introdujo por primera vez en la versión v0.0.4.

Volver a la tabla de contenido

preread_by_lua_no_postpone

sintaxis: preread_by_lua_no_postpone on|off

contexto: stream

Controla si se debe desactivar el aplazamiento de las directivas preread_by_lua* para ejecutarse al final de la fase de procesamiento preread. Por defecto, esta directiva está desactivada y el código Lua se aplaza para ejecutarse al final de la fase preread.

Esta directiva se introdujo por primera vez en la versión v0.0.4.

Volver a la tabla de contenido

Nginx API para Lua

Muchas funciones de la API de Lua están portadas desde ngx_http_lua. Consulta el manual oficial de ngx_http_lua para más detalles sobre estas funciones de la API de Lua.

Este módulo admite completamente el nuevo subsistema de variables dentro del núcleo de stream de Nginx. Puedes acceder a cualquier variable incorporada proporcionada por el núcleo de stream o otros módulos de stream. * Constantes del núcleo

`ngx.OK`, `ngx.ERROR`, etc.

Solo se admiten sockets de solicitud en bruto, por razones obvias. El valor del argumento raw se ignora y siempre se devuelve el socket de solicitud en bruto. A diferencia de ngx_http_lua, todavía puedes llamar a funciones de salida como ngx.say, ngx.print, y ngx.flush después de adquirir el socket de solicitud en bruto a través de esta función.

Cuando el servidor de stream está en modo UDP, leer desde el socket downstream devuelto por la llamada ngx.req.socket solo devolverá el contenido de un solo paquete. Por lo tanto, la llamada de lectura nunca bloqueará y devolverá nil, "no more data" cuando todos los datos del datagrama hayan sido consumidos. Sin embargo, puedes optar por enviar múltiples paquetes UDP de vuelta al cliente utilizando el socket downstream.

Los sockets TCP en bruto devueltos por este módulo contendrán el siguiente método extra:

Volver a la tabla de contenido

reqsock:receiveany

sintaxis: data, err = reqsock:receiveany(max)

contexto: content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*

Este método es similar al método tcpsock:receiveany

Este método se introdujo en stream-lua-nginx-module desde v0.0.8.

Volver a la tabla de contenido

tcpsock:shutdown

sintaxis: ok, err = tcpsock:shutdown("send")

contexto: content_by_lua*

Cierra la parte de escritura del socket de solicitud, previene toda escritura adicional al cliente y envía TCP FIN, mientras mantiene la mitad de lectura abierta.

Actualmente solo se admite la dirección "send". Usar cualquier parámetro diferente de "send" devolverá un error.

Si has llamado a alguna función de salida (como ngx.say) antes de llamar a este método, considera usar ngx.flush(true) para asegurarte de que todos los búferes ocupados se vacíen completamente antes de cerrar el socket. Si se detectaron búferes ocupados, este método devolverá nil con el mensaje de error "socket busy writing".

Esta característica es particularmente útil para protocolos que generan una respuesta antes de realmente terminar de consumir todos los datos entrantes. Normalmente, el kernel enviará RST al cliente cuando tcpsock:close se llama sin vaciar primero el búfer de recepción. Llamar a este método te permitirá seguir leyendo desde el búfer de recepción y previene que se envíe RST.

También puedes usar este método para simular un cierre persistente similar a aquel proporcionado por el ngx_http_core_module para protocolos que necesitan tal comportamiento. Aquí hay un ejemplo:

local LINGERING_TIME = 30 -- 30 segundos
local LINGERING_TIMEOUT = 5000 -- 5 segundos

local ok, err = sock:shutdown("send")
if not ok then
    ngx.log(ngx.ERR, "falló el cierre: ", err)
    return
end

local deadline = ngx.time() + LINGERING_TIME

sock:settimeouts(nil, nil, LINGERING_TIMEOUT)

repeat
    local data, _, partial = sock:receive(1024)
until (not data and not partial) or ngx.time() >= deadline

Volver a la tabla de contenido

reqsock:peek

sintaxis: ok, err = reqsock:peek(size)

contexto: preread_by_lua*

Mira en el búfer de preread que contiene datos downstream enviados por el cliente sin consumirlos. Es decir, los datos devueltos por esta API aún serán enviados hacia arriba en fases posteriores.

Esta función toma un único argumento requerido, size, que es el número de bytes a mirar. Las llamadas repetidas a esta función siempre devuelven datos desde el principio del búfer de preread.

Ten en cuenta que la fase de preread ocurre después del apretón de manos TLS. Si el servidor de stream fue configurado con TLS habilitado, los datos devueltos estarán en texto claro.

Si el búfer de preread no tiene la cantidad solicitada de datos, entonces el hilo Lua actual será suspendido hasta que haya más datos disponibles, se haya excedido preread_buffer_size, o haya transcurrido preread_timeout. Las llamadas exitosas siempre devuelven las cantidades solicitadas de datos, es decir, no se devolverán datos parciales.

Cuando se haya excedido preread_buffer_size, la sesión de stream actual será terminada con el código de estado de sesión 400 inmediatamente por el módulo central de stream, con el mensaje de error "preread buffer full" que se imprimirá en el registro de errores.

Cuando se haya excedido preread_timeout, la sesión de stream actual será terminada con el código de estado de sesión 200 inmediatamente por el módulo central de stream.

En ambos casos, no se puede realizar más procesamiento en la sesión (excepto log_by_lua*). La conexión será cerrada automáticamente por el módulo central de stream.

Ten en cuenta que esta API no se puede usar si se ha consumido datos del cliente. Por ejemplo, después de llamar reqsock:receive. Si se intenta hacer tal cosa, se lanzará el error Lua "attempt to peek on a consumed socket". Consumir datos del cliente después de llamar a esta API está permitido y es seguro.

Aquí hay un ejemplo de uso de esta API:

local sock = assert(ngx.req.socket())

local data = assert(sock:peek(1)) -- mira el primer byte que contiene la longitud
data = string.byte(data)

data = assert(sock:peek(data + 1)) -- mira la longitud + el byte de tamaño

local payload = data:sub(2) -- recorta el byte de longitud para obtener el payload real

ngx.log(ngx.INFO, "el payload es: ", payload)

Esta API se introdujo por primera vez en la versión v0.0.6.

Volver a la tabla de contenido

Compatibilidad con Nginx

La última versión de este módulo es compatible con las siguientes versiones de Nginx:

  • 1.29.x (última prueba: 1.29.2)
  • 1.27.x (última prueba: 1.27.1)
  • 1.25.x (última prueba: 1.25.1)
  • 1.21.x (última prueba: 1.21.4)
  • 1.19.x (última prueba: 1.19.3)
  • 1.17.x (última prueba: 1.17.8)
  • 1.15.x (última prueba: 1.15.8)
  • 1.13.x (última prueba: 1.13.6)

Los núcleos de Nginx anteriores a 1.13.6 (exclusivo) no están probados y pueden o no funcionar. ¡Usa bajo tu propio riesgo!

indicarle al sistema de construcción de nginx dónde encontrar LuaJIT 2.1:

export LUAJIT_LIB=/path/to/luajit/lib export LUAJIT_INC=/path/to/luajit/include/luajit-2.1

Aquí asumimos que Nginx se instalará bajo /opt/nginx/.

./configure --prefix=/opt/nginx \ --with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \ --with-stream \ --with-stream_ssl_module \ --add-module=/path/to/stream-lua-nginx-module

Repositorio de Código

El repositorio de código de este proyecto está alojado en GitHub en openresty/stream-lua-nginx-module.

Ver También

GitHub

Puedes encontrar consejos adicionales de configuración y documentación para este módulo en el repositorio de GitHub para nginx-module-stream-lua.