Zum Inhalt

stream-lua: Lua-Skripting-Unterstützung für NGINX-Streams

Installation

Sie können dieses Modul in jeder RHEL-basierten Distribution installieren, einschließlich, aber nicht beschränkt auf:

  • RedHat Enterprise Linux 7, 8, 9 und 10
  • CentOS 7, 8, 9
  • AlmaLinux 8, 9
  • Rocky Linux 8, 9
  • Amazon Linux 2 und 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

Aktivieren Sie das Modul, indem Sie Folgendes an den Anfang von /etc/nginx/nginx.conf hinzufügen:

load_module modules/ngx_stream_lua_module.so;

Dieses Dokument beschreibt nginx-module-stream-lua v0.0.18 veröffentlicht am 27. März 2026.


Zusammenfassung

events {
    worker_connections 1024;
}

stream {
    # definiere einen TCP-Server, der auf dem Port 1234 lauscht:
    server {
        listen 1234;

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

Einrichten als SSL TCP-Server:

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()  -- lese eine Zeile von downstream
            if data == "thunder!" then
                ngx.say("flash!")  -- gebe Daten aus
            else
                ngx.say("boom!")
            end
            ngx.say("das Ende...")
        }
    }
}

Das Lauschen auf einem UNIX-Domain-Socket wird ebenfalls unterstützt:

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

        content_by_lua_block {
            ngx.say("Was geht?")
            ngx.flush(true)  -- alle ausstehenden Ausgaben leeren und warten
            ngx.sleep(3)  -- 3 Sekunden schlafen
            ngx.say("Tschüss...")
        }
    }
}

Beschreibung

Dies ist ein Port des ngx_http_lua_module zum Nginx "Stream"-Subsystem, um generische Stream/TCP-Clients zu unterstützen.

Die verfügbaren Lua-APIs und Nginx-Direktiven bleiben die gleichen wie die des ngx_http_lua-Moduls.

Direktiven

Die folgenden Direktiven wurden direkt von ngx_http_lua portiert. Bitte überprüfen Sie die Dokumentation von ngx_http_lua für weitere Details zu deren Verwendung und Verhalten.

Die send_timeout Direktive im Nginx "http" Subsystem fehlt im "stream" Subsystem. Daher verwendet ngx_stream_lua_module stattdessen die Direktive lua_socket_send_timeout für diesen Zweck.

Hinweis: Die lingering close-Direktive, die in älteren Versionen des stream_lua_nginx_module existierte, wurde entfernt und kann nun bei Bedarf mit der neu hinzugefügten tcpsock:shutdown API simuliert werden.

preread_by_lua_block

Syntax: preread_by_lua_block { lua-script }

Kontext: stream, server

Phase: preread

Funktioniert als Handler für die preread-Phase und führt den in lua-script angegebenen Lua-Code-String für jede Verbindung (oder Paket im Datagramm-Modus) aus. Der Lua-Code kann API-Aufrufe machen und wird als neue, gestartete Coroutine in einer unabhängigen globalen Umgebung (d.h. einem Sandbox) ausgeführt.

Es ist möglich, den Rohanforderungssocket mit ngx.req.socket zu erwerben und Daten vom Client zu empfangen oder an ihn zu senden. Beachten Sie jedoch, dass der Aufruf der receive()-Methode des Anforderungssockets die Daten aus dem Puffer verbraucht und diese verbrauchten Daten von den Handlers weiter unten in der Kette nicht gesehen werden.

Der preread_by_lua_block-Code wird immer am Ende der preread-Verarbeitungsphase ausgeführt, es sei denn, preread_by_lua_no_postpone ist aktiviert.

Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

preread_by_lua_file

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

Kontext: stream, server

Phase: preread

Entspricht preread_by_lua_block, mit dem Unterschied, dass die Datei, die durch <path-to-lua-script-file> angegeben ist, den Lua-Code oder LuaJIT-Bytecode enthält, der ausgeführt werden soll.

Nginx-Variablen können in der <path-to-lua-script-file>-Zeichenfolge verwendet werden, um Flexibilität zu bieten. Dies birgt jedoch einige Risiken und wird normalerweise nicht empfohlen.

Wenn ein relativer Pfad wie foo/bar.lua angegeben wird, wird er in den absoluten Pfad umgewandelt, der relativ zum server prefix-Pfad ist, der durch die -p PATH-Befehlszeilenoption bestimmt wird, die beim Starten des Nginx-Servers angegeben wird.

Wenn der Lua-Code-Cache aktiviert ist (standardmäßig), wird der Benutzer-Code beim ersten Verbindungsaufbau einmal geladen und zwischengespeichert. Die Nginx-Konfiguration muss jedes Mal neu geladen werden, wenn die Lua-Quelldatei geändert wird. Der Lua-Code-Cache kann während der Entwicklung vorübergehend deaktiviert werden, indem lua_code_cache in nginx.conf auf off gesetzt wird, um ein erneutes Laden von Nginx zu vermeiden.

Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

log_by_lua_block

Syntax: log_by_lua_block { lua-script }

Kontext: stream, server

Phase: log

Führt den in <lua-script> angegebenen Lua-Quellcode während der log-Anforderungsverarbeitungsphase aus. Dies ersetzt nicht die aktuellen Zugriffsprotokolle, sondern wird vorher ausgeführt.

Yielding-APIs wie ngx.req.socket, ngx.socket.*, ngx.sleep oder ngx.say sind in dieser Phase nicht verfügbar.

Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

log_by_lua_file

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

Kontext: stream, server

Phase: log

Entspricht log_by_lua_block, mit dem Unterschied, dass die Datei, die durch <path-to-lua-script-file> angegeben ist, den Lua-Code oder LuaJIT-Bytecode enthält, der ausgeführt werden soll.

Nginx-Variablen können in der <path-to-lua-script-file>-Zeichenfolge verwendet werden, um Flexibilität zu bieten. Dies birgt jedoch einige Risiken und wird normalerweise nicht empfohlen.

Wenn ein relativer Pfad wie foo/bar.lua angegeben wird, wird er in den absoluten Pfad umgewandelt, der relativ zum server prefix-Pfad ist, der durch die -p PATH-Befehlszeilenoption bestimmt wird, die beim Starten des Nginx-Servers angegeben wird.

Wenn der Lua-Code-Cache aktiviert ist (standardmäßig), wird der Benutzer-Code beim ersten Verbindungsaufbau einmal geladen und zwischengespeichert. Die Nginx-Konfiguration muss jedes Mal neu geladen werden, wenn die Lua-Quelldatei geändert wird. Der Lua-Code-Cache kann während der Entwicklung vorübergehend deaktiviert werden, indem lua_code_cache in nginx.conf auf off gesetzt wird, um ein erneutes Laden von Nginx zu vermeiden.

Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

lua_add_variable

Syntax: lua_add_variable $var

Kontext: stream

Fügt die Variable $var zum "stream"-Subsystem hinzu und macht sie änderbar. Wenn $var bereits existiert, wird diese Direktive nichts tun.

Standardmäßig werden Variablen, die mit dieser Direktive hinzugefügt werden, als "nicht gefunden" betrachtet, und das Lesen von ihnen mit ngx.var gibt nil zurück. Sie können jedoch jederzeit über die ngx.var.VARIABLE API neu zugewiesen werden.

Diese Direktive wurde erstmals in der v0.0.4 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

preread_by_lua_no_postpone

Syntax: preread_by_lua_no_postpone on|off

Kontext: stream

Steuert, ob das Verschieben von preread_by_lua* Direktiven am Ende der preread-Verarbeitungsphase deaktiviert werden soll. Standardmäßig ist diese Direktive deaktiviert und der Lua-Code wird verschoben, um am Ende der preread-Phase ausgeführt zu werden.

Diese Direktive wurde erstmals in der v0.0.4 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

Nginx API für Lua

Viele Lua-API-Funktionen wurden von ngx_http_lua portiert. Schauen Sie sich das offizielle Handbuch von ngx_http_lua für weitere Details zu diesen Lua-API-Funktionen an.

Dieses Modul unterstützt vollständig das neue Variablen-Subsystem im Nginx-Stream-Kern. Sie können auf alle builtin-Variablen zugreifen, die vom Stream-Kern oder anderen Stream-Modulen bereitgestellt werden. * Kernkonstanten

`ngx.OK`, `ngx.ERROR` usw.

Es werden nur rohe Anforderungssockets unterstützt, aus offensichtlichen Gründen. Der Wert des raw-Arguments wird ignoriert und der rohe Anforderungssocket wird immer zurückgegeben. Im Gegensatz zu ngx_http_lua können Sie weiterhin Ausgabefunktionen wie ngx.say, ngx.print und ngx.flush aufrufen, nachdem Sie den rohen Anforderungssocket über diese Funktion erworben haben.

Wenn der Stream-Server im UDP-Modus ist, gibt das Lesen vom downstream-Socket, der durch den ngx.req.socket-Aufruf zurückgegeben wird, nur den Inhalt eines einzelnen Pakets zurück. Daher wird der Leseaufruf niemals blockieren und gibt nil, "no more data" zurück, wenn alle Daten aus dem Datagramm verbraucht wurden. Sie können jedoch mehrere UDP-Pakete an den Client zurücksenden, indem Sie den downstream-Socket verwenden.

Die von diesem Modul zurückgegebenen rohen TCP-Sockets enthalten die folgende zusätzliche Methode:

Zurück zum Inhaltsverzeichnis

reqsock:receiveany

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

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

Diese Methode ähnelt der tcpsock:receiveany Methode.

Diese Methode wurde in stream-lua-nginx-module seit v0.0.8 eingeführt.

Zurück zum Inhaltsverzeichnis

tcpsock:shutdown

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

Kontext: content_by_lua*

Schaltet den Schreibteil des Anforderungssockets ab, verhindert weiteres Schreiben an den Client und sendet TCP FIN, während die Lesehälfte offen bleibt.

Derzeit wird nur die Richtung "send" unterstützt. Die Verwendung anderer Parameter als "send" führt zu einem Fehler.

Wenn Sie vor dem Aufruf dieser Methode Ausgabefunktionen (wie ngx.say) aufgerufen haben, sollten Sie ngx.flush(true) verwenden, um sicherzustellen, dass alle aktiven Puffer vollständig geleert werden, bevor der Socket heruntergefahren wird. Wenn aktive Puffer erkannt wurden, gibt diese Methode nil mit der Fehlermeldung "socket busy writing" zurück.

Dieses Feature ist besonders nützlich für Protokolle, die eine Antwort generieren, bevor sie tatsächlich alle eingehenden Daten konsumiert haben. Normalerweise sendet der Kernel RST an den Client, wenn tcpsock:close aufgerufen wird, ohne zuerst den Empfangspuffer zu leeren. Der Aufruf dieser Methode ermöglicht es Ihnen, weiterhin aus dem Empfangspuffer zu lesen und verhindert, dass RST gesendet wird.

Sie können diese Methode auch verwenden, um ein lingering close zu simulieren, ähnlich dem, bereitgestellt durch das ngx_http_core_module für Protokolle, die ein solches Verhalten benötigen. Hier ist ein Beispiel:

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

local ok, err = sock:shutdown("send")
if not ok then
    ngx.log(ngx.ERR, "Shutdown fehlgeschlagen: ", 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

Zurück zum Inhaltsverzeichnis

reqsock:peek

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

Kontext: preread_by_lua*

Blickt in den preread Puffer, der downstream-Daten enthält, die vom Client gesendet wurden, ohne sie zu konsumieren. Das heißt, die von dieser API zurückgegebenen Daten werden in späteren Phasen weiterhin upstream weitergeleitet.

Diese Funktion benötigt ein einzelnes erforderliches Argument, size, das die Anzahl der Bytes angibt, die eingesehen werden sollen. Wiederholte Aufrufe dieser Funktion geben immer Daten vom Anfang des preread-Puffers zurück.

Beachten Sie, dass die preread-Phase nach dem TLS-Handshake erfolgt. Wenn der Stream-Server mit aktiviertem TLS konfiguriert wurde, werden die zurückgegebenen Daten im Klartext vorliegen.

Wenn der preread-Puffer nicht die angeforderte Menge an Daten hat, wird der aktuelle Lua-Thread unterbrochen, bis mehr Daten verfügbar sind, preread_buffer_size überschritten wurde oder preread_timeout verstrichen ist. Erfolgreiche Aufrufe geben immer die angeforderte Menge an Daten zurück, das heißt, es werden keine teilweisen Daten zurückgegeben.

Wenn preread_buffer_size überschritten wurde, wird die aktuelle Stream-Sitzung sofort mit dem Statuscode der Sitzung 400 vom Stream-Kernmodul beendet, mit der Fehlermeldung "preread buffer full", die im Fehlerprotokoll ausgegeben wird.

Wenn preread_timeout überschritten wurde, wird die aktuelle Stream-Sitzung sofort mit dem Statuscode der Sitzung 200 vom Stream-Kernmodul beendet.

In beiden Fällen ist keine weitere Verarbeitung der Sitzung möglich (außer log_by_lua*). Die Verbindung wird automatisch vom Stream-Kernmodul geschlossen.

Beachten Sie, dass diese API nicht verwendet werden kann, wenn der Verbrauch von Clientdaten bereits erfolgt ist. Zum Beispiel, nachdem reqsock:receive aufgerufen wurde. Wenn ein solcher Versuch unternommen wurde, wird der Lua-Fehler "attempt to peek on a consumed socket" ausgelöst. Der Verbrauch von Clientdaten nach dem Aufruf dieser API ist erlaubt und sicher.

Hier ist ein Beispiel für die Verwendung dieser API:

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

local data = assert(sock:peek(1)) -- die ersten 1 Byte, die die Länge enthalten, einsehen
data = string.byte(data)

data = assert(sock:peek(data + 1)) -- die Länge + das Größenbyte einsehen

local payload = data:sub(2) -- das Größenbyte trimmen, um die tatsächliche Nutzlast zu erhalten

ngx.log(ngx.INFO, "Nutzlast ist: ", payload)

Diese API wurde erstmals in der v0.0.6 Veröffentlichung eingeführt.

Zurück zum Inhaltsverzeichnis

Nginx-Kompatibilität

Die neueste Version dieses Moduls ist kompatibel mit den folgenden Versionen von Nginx:

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

Nginx-Kerne älter als 1.13.6 (exklusiv) sind nicht getestet und funktionieren möglicherweise nicht. Verwendung auf eigenes Risiko!

Teilen Sie Nginx's Build-System mit, wo LuaJIT 2.1 zu finden ist:

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

Hier gehen wir davon aus, dass Nginx unter /opt/nginx/ installiert werden soll.

./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

Code-Repository

Das Code-Repository dieses Projekts wird auf GitHub unter openresty/stream-lua-nginx-module gehostet.

Siehe auch

GitHub

Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub Repository für nginx-module-stream-lua.