stream-lua: Lua-Skriptingunterstü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.
Synopsis
events {
worker_connections 1024;
}
stream {
# definiere einen TCP-Server, der auf Port 1234 lauscht:
server {
listen 1234;
content_by_lua_block {
ngx.say("Hallo, Lua!")
}
}
}
Als SSL-TCP-Server einrichten:
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 ihrer Verwendung und Verhalten.
- lua_load_resty_core
- lua_code_cache
- lua_regex_cache_max_entries
- lua_package_path
- lua_package_cpath
- init_by_lua_block
- init_by_lua_file
- init_worker_by_lua_block
- init_worker_by_lua_file
- preread_by_lua_block
- preread_by_lua_file
- content_by_lua_block
- content_by_lua_file
- balancer_by_lua_block
- balancer_by_lua_file
- log_by_lua_block
- log_by_lua_file
- ssl_client_hello_by_lua_block
- ssl_client_hello_by_lua_file
- ssl_certificate_by_lua_block
- ssl_certificate_by_lua_file
- proxy_ssl_certificate_by_lua_block
- proxy_ssl_certificate_by_lua_file
- proxy_ssl_verify_by_lua_block
- proxy_ssl_verify_by_lua_file
- lua_shared_dict
- lua_socket_connect_timeout
- lua_socket_buffer_size
- lua_socket_pool_size
- lua_socket_keepalive_timeout
- lua_socket_log_errors
- lua_ssl_ciphers
- lua_ssl_crl
- lua_ssl_protocols
- lua_ssl_certificate
- lua_ssl_certificate_key
- lua_ssl_trusted_certificate
- lua_ssl_verify_depth
- lua_ssl_key_log
- lua_ssl_conf_command
- lua_upstream_skip_openssl_default_verify
- lua_check_client_abort
- lua_max_pending_timers
- lua_max_running_timers
- lua_sa_restart
- lua_add_variable
- lua_capture_error_log
- preread_by_lua_no_postpone
Die send_timeout Direktive im Nginx
"http" Subsystem fehlt im "stream" Subsystem. Daher verwendet
ngx_stream_lua_module stattdessen die lua_socket_send_timeout Direktive für diesen
Zweck.
Hinweis: Die lingering close-Direktive, die in älteren Versionen des
stream_lua_nginx_module existierte, wurde entfernt und kann jetzt bei Bedarf mit der
neu hinzugefügten tcpsock:shutdown API simuliert werden.
preread_by_lua_block
syntax: preread_by_lua_block { lua-script }
context: stream, server
phase: preread
Fungiert 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 Datagrammmodus) 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 rohen Anfrage-Socket mit ngx.req.socket
zu erwerben und Daten vom Client zu empfangen oder an den Client zu senden. Beachten Sie jedoch, dass der Aufruf der receive()-Methode
des Anfrage-Sockets die Daten aus dem Puffer verbraucht und diese verbrauchten Daten von den Handlern
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.
preread_by_lua_file
syntax: preread_by_lua_file <path-to-lua-script-file>
context: 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 im <path-to-lua-script-file>-String 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 relativ zum server prefix-Pfad umgewandelt, der durch die -p PATH-Befehlszeilenoption bestimmt wird, die beim Starten des Nginx-Servers angegeben wurde.
Wenn der Lua-Code-Cache aktiviert ist (standardmäßig), wird der Benutzer-Code einmal bei der ersten Verbindung 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 auf off in nginx.conf umgeschaltet wird, um ein erneutes Laden von Nginx zu vermeiden.
Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.
log_by_lua_block
syntax: log_by_lua_block { lua-script }
context: stream, server
phase: log
Führt den als <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.
log_by_lua_file
syntax: log_by_lua_file <path-to-lua-script-file>
context: 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 im <path-to-lua-script-file>-String 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 relativ zum server prefix-Pfad umgewandelt, der durch die -p PATH-Befehlszeilenoption bestimmt wird, die beim Starten des Nginx-Servers angegeben wurde.
Wenn der Lua-Code-Cache aktiviert ist (standardmäßig), wird der Benutzer-Code einmal bei der ersten Verbindung 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 auf off in nginx.conf umgeschaltet wird, um ein erneutes Laden von Nginx zu vermeiden.
Diese Direktive wurde erstmals in der v0.0.3 Veröffentlichung eingeführt.
lua_add_variable
syntax: lua_add_variable $var
context: 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.
preread_by_lua_no_postpone
syntax: preread_by_lua_no_postpone on|off
context: stream
Steuert, ob das Verschieben von preread_by_lua* Direktiven
zum Ausführen am Ende der preread-Verarbeitungsphase deaktiviert werden soll oder nicht. 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.
Nginx API für Lua
Viele Lua-API-Funktionen wurden von ngx_http_lua portiert. Überprüfen Sie das offizielle Handbuch von ngx_http_lua für weitere Details zu diesen Lua-API-Funktionen.
Dieses Modul unterstützt vollständig das neue Variablen-Subsystem im Nginx-Stream-Kern. Sie können auf alle built-in variables zugreifen, die vom Stream-Kern oder anderen Stream-Modulen bereitgestellt werden. * Core constants
`ngx.OK`, `ngx.ERROR`, usw.
-
ngx.ERR,ngx.WARN, usw. * print * ngx.ctx * ngx.balancer
Nur rohe Anfrage-Sockets werden aus offensichtlichen Gründen unterstützt. Der Wert des raw-Arguments
wird ignoriert und der rohe Anfrage-Socket 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 Anfrage-Socket ü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:
reqsock:receiveany
syntax: data, err = reqsock:receiveany(max)
context: 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.
tcpsock:shutdown
syntax: ok, err = tcpsock:shutdown("send")
context: content_by_lua*
Schaltet den Schreibteil des Anfrage-Sockets ab, verhindert alle weiteren Schreibvorgänge 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 beschäftigten Puffer vollständig
geleert werden, bevor der Socket heruntergefahren wird. Wenn beschäftigte Puffer erkannt werden, 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 verbrauchen. 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
reqsock:peek
syntax: ok, err = reqsock:peek(size)
context: preread_by_lua*
Blickt in den preread Puffer, der die von dem Client gesendeten downstream-Daten enthält, ohne sie zu verbrauchen. Das heißt, die von dieser API zurückgegebenen Daten werden in späteren Phasen weiterhin upstream weitergeleitet.
Diese Funktion nimmt 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 sein.
Wenn der preread-Puffer nicht die angeforderte Menge an Daten hat, wird der aktuelle Lua-Thread
ausgesetzt, 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, d.h. es werden keine Teilmengen
von Daten zurückgegeben.
Wenn preread_buffer_size
überschritten wurde, wird die aktuelle Stream-Sitzung sofort mit dem
Session-Statuscode 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
Session-Statuscode 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 Client-Daten 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. Das Verbrauchen von Client-Daten 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)) -- schaue mir die ersten 1 Byte an, die die Länge enthalten
data = string.byte(data)
data = assert(sock:peek(data + 1)) -- schaue mir die Länge + das Größenbyte an
local payload = data:sub(2) -- trimme das Längenbyte, 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.
- ngx.print
- ngx.say
- ngx.log
-
Dieser Aufruf ignoriert derzeit das
wait-Argument und wartet immer darauf, dass alle ausstehenden Ausgaben vollständig geleert werden (in die System-Socket-Sendepuffer). * ngx.exit * ngx.eof * ngx.sleep * ngx.escape_uri * ngx.unescape_uri * ngx.encode_args * ngx.decode_args * ngx.encode_base64 * ngx.decode_base64 * ngx.crc32_short * ngx.crc32_long * ngx.hmac_sha1 * ngx.md5 * ngx.md5_bin * ngx.sha1_bin * ngx.quote_sql_str * ngx.today * ngx.time * ngx.now * ngx.update_time * ngx.localtime * ngx.utctime * ngx.re.match * ngx.re.find * ngx.re.gmatch * ngx.re.sub * ngx.re.gsub * ngx.shared.DICT * ngx.socket.tcp * ngx.socket.udp * ngx.socket.connect * ngx.get_phase * ngx.thread.spawn * ngx.thread.wait * ngx.thread.kill * ngx.on_abort * ngx.timer.at * ngx.timer.running_count * ngx.timer.pending_count * ngx.config.debug * ngx.config.subsystemNimmt in diesem Modul immer den Lua-Stringwert
"stream"an. * ngx.config.prefix * ngx.config.nginx_version * ngx.config.nginx_configure * ngx.config.ngx_lua_version * ngx.worker.exiting * ngx.worker.pid * ngx.worker.pids * ngx.worker.count * ngx.worker.id * coroutine.create * coroutine.resume * coroutine.yield * coroutine.wrap * coroutine.running * coroutine.status
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. Benutzen Sie 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.