stream-lua: Поддержка сценариев Lua для потоков NGINX
Установка
Вы можете установить этот модуль в любой дистрибутив на базе RHEL, включая, но не ограничиваясь:
- RedHat Enterprise Linux 7, 8, 9 и 10
- CentOS 7, 8, 9
- AlmaLinux 8, 9
- Rocky Linux 8, 9
- Amazon Linux 2 и 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
Включите модуль, добавив следующее в начало файла /etc/nginx/nginx.conf:
load_module modules/ngx_stream_lua_module.so;
Этот документ описывает nginx-module-stream-lua v0.0.18, выпущенный 27 марта 2026 года.
Синопсис
events {
worker_connections 1024;
}
stream {
# определите TCP сервер, слушающий на порту 1234:
server {
listen 1234;
content_by_lua_block {
ngx.say("Hello, Lua!")
}
}
}
Настройка в качестве SSL TCP сервера:
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() -- прочитать строку из потока
if data == "thunder!" then
ngx.say("flash!") -- вывод данных
else
ngx.say("boom!")
end
ngx.say("the end...")
}
}
}
Поддерживается также прослушивание на сокете UNIX:
stream {
server {
listen unix:/tmp/nginx.sock;
content_by_lua_block {
ngx.say("What's up?")
ngx.flush(true) -- сбросить любые ожидающие выходные данные и подождать
ngx.sleep(3) -- спать 3 секунды
ngx.say("Bye bye...")
}
}
}
Описание
Это порт модуля ngx_http_lua_module в подсистему "stream" Nginx для поддержки универсальных клиентов потоков/TCP.
Доступные API Lua и директивы Nginx остаются такими же, как и в модуле ngx_http_lua.
Директивы
Следующие директивы были перенесены напрямую из ngx_http_lua. Пожалуйста, проверьте документацию ngx_http_lua для получения более подробной информации о их использовании и поведении.
- 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
Директива send_timeout в подсистеме Nginx "http" отсутствует в подсистеме "stream". Таким образом, ngx_stream_lua_module использует директиву lua_socket_send_timeout для этой цели.
Примечание: директива lingering close, которая существовала в более старых версиях stream_lua_nginx_module, была удалена и теперь может быть смоделирована с помощью нового API tcpsock:shutdown, если это необходимо.
preread_by_lua_block
синтаксис: preread_by_lua_block { lua-script }
контекст: stream, server
фаза: preread
Действует как обработчик фазы preread и выполняет строку кода Lua, указанную в lua-script, для каждого соединения
(или пакета в режиме дейтаграмм).
Код Lua может выполнять вызовы API и выполняется как новая созданная корутина в независимой глобальной среде (т.е. в песочнице).
Возможно получить необработанный сокет запроса с помощью ngx.req.socket
и получать данные от клиента или отправлять данные клиенту. Однако имейте в виду, что вызов метода receive()
сокета запроса потребляет данные из буфера, и такие потребленные данные не будут видны обработчикам
дальше по цепочке.
Код preread_by_lua_block всегда будет выполняться в конце фазы обработки preread, если
preread_by_lua_no_postpone не включен.
Эта директива была впервые введена в релизе v0.0.3.
preread_by_lua_file
синтаксис: preread_by_lua_file <path-to-lua-script-file>
контекст: stream, server
фаза: preread
Эквивалентно preread_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua
или байт-код LuaJIT для выполнения.
Переменные Nginx могут использоваться в строке <path-to-lua-script-file> для обеспечения гибкости. Однако это несет в себе некоторые риски и обычно не рекомендуется.
Когда указано относительное имя файла, например foo/bar.lua, оно будет преобразовано в абсолютный путь относительно пути server prefix, определенного параметром командной строки -p PATH, указанным при запуске сервера Nginx.
Когда кэш кода Lua включен (по умолчанию), пользовательский код загружается один раз при первом соединении и кэшируется. Конфигурация Nginx должна быть перезагружена каждый раз, когда файл исходного кода Lua изменяется. Кэш кода Lua можно временно отключить во время разработки, переключив lua_code_cache на off в nginx.conf, чтобы избежать необходимости перезагружать Nginx.
Эта директива была впервые введена в релизе v0.0.3.
log_by_lua_block
синтаксис: log_by_lua_block { lua-script }
контекст: stream, server
фаза: log
Запускает исходный код Lua, указанный как <lua-script>, во время фазы обработки запроса log. Это не заменяет текущие журналы доступа, а выполняется перед ними.
API, которые могут приостанавливать выполнение, такие как ngx.req.socket, ngx.socket.*, ngx.sleep или ngx.say, недоступны на этой фазе.
Эта директива была впервые введена в релизе v0.0.3.
log_by_lua_file
синтаксис: log_by_lua_file <path-to-lua-script-file>
контекст: stream, server
фаза: log
Эквивалентно log_by_lua_block, за исключением того, что файл, указанный в <path-to-lua-script-file>, содержит код Lua
или байт-код LuaJIT для выполнения.
Переменные Nginx могут использоваться в строке <path-to-lua-script-file> для обеспечения гибкости. Однако это несет в себе некоторые риски и обычно не рекомендуется.
Когда указано относительное имя файла, например foo/bar.lua, оно будет преобразовано в абсолютный путь относительно пути server prefix, определенного параметром командной строки -p PATH, указанным при запуске сервера Nginx.
Когда кэш кода Lua включен (по умолчанию), пользовательский код загружается один раз при первом соединении и кэшируется. Конфигурация Nginx должна быть перезагружена каждый раз, когда файл исходного кода Lua изменяется. Кэш кода Lua можно временно отключить во время разработки, переключив lua_code_cache на off в nginx.conf, чтобы избежать необходимости перезагружать Nginx.
Эта директива была впервые введена в релизе v0.0.3.
lua_add_variable
синтаксис: lua_add_variable $var
контекст: stream
Добавляет переменную $var в подсистему "stream" и делает ее изменяемой. Если $var уже существует,
эта директива ничего не сделает.
По умолчанию переменные, добавленные с помощью этой директивы, считаются "не найденными", и чтение их
с помощью ngx.var вернет nil. Однако их можно переназначить через API ngx.var.VARIABLE в любое время.
Эта директива была впервые введена в релизе v0.0.4.
preread_by_lua_no_postpone
синтаксис: preread_by_lua_no_postpone on|off
контекст: stream
Управляет тем, следует ли отключить отложенные директивы preread_by_lua*
для выполнения в конце фазы обработки preread. По умолчанию эта директива отключена,
и код Lua откладывается для выполнения в конце фазы preread.
Эта директива была впервые введена в релизе v0.0.4.
Nginx API для Lua
Многие функции API Lua были перенесены из ngx_http_lua. Ознакомьтесь с официальным руководством ngx_http_lua для получения более подробной информации о этих функциях API Lua.
Этот модуль полностью поддерживает новую подсистему переменных внутри ядра потока Nginx. Вы можете получить доступ к любым встроенным переменным, предоставленным ядром потока или другими модулями потока. * Основные константы
`ngx.OK`, `ngx.ERROR` и т.д.
-
Константы уровней журналов Nginx
ngx.ERR,ngx.WARNи т.д. * print * ngx.ctx * ngx.balancer
Поддерживаются только необработанные сокеты запросов, по очевидным причинам. Значение аргумента raw
игнорируется, и всегда возвращается необработанный сокет запроса. В отличие от ngx_http_lua,
вы все равно можете вызывать функции API вывода, такие как ngx.say, ngx.print и ngx.flush
после получения необработанного сокета запроса через эту функцию.
Когда сервер потока находится в режиме UDP, чтение из сокета downstream, возвращаемого вызовом
ngx.req.socket, будет возвращать только содержимое одного пакета. Поэтому
вызов чтения никогда не будет блокироваться и вернет nil, "no more data", когда все
данные из дейтаграммы будут потреблены. Тем не менее, вы можете выбрать отправку нескольких UDP
пакетов обратно клиенту, используя сокет downstream.
Необработанные TCP сокеты, возвращаемые этим модулем, будут содержать следующий дополнительный метод:
reqsock:receiveany
синтаксис: data, err = reqsock:receiveany(max)
контекст: content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*
Этот метод аналогичен методу tcpsock:receiveany.
Этот метод был введен в stream-lua-nginx-module с версии v0.0.8.
tcpsock:shutdown
синтаксис: ok, err = tcpsock:shutdown("send")
контекст: content_by_lua*
Закрывает часть записи сокета запроса, предотвращает дальнейшую запись клиенту и отправляет TCP FIN, при этом оставляя часть чтения открытой.
В настоящее время поддерживается только направление "send". Использование любых параметров, кроме "send", вернет
ошибку.
Если вы вызывали какие-либо функции вывода (например, ngx.say)
перед вызовом этого метода, рассмотрите возможность использования ngx.flush(true), чтобы убедиться, что все занятые буферы полностью
сброшены перед закрытием сокета. Если были обнаружены какие-либо занятые буферы, этот метод вернет nil
с сообщением об ошибке "socket busy writing".
Эта функция особенно полезна для протоколов, которые генерируют ответ до фактического завершения обработки всех входящих данных. Обычно ядро отправляет RST клиенту, когда tcpsock:close вызывается без предварительной очистки буфера приема. Вызов этого метода позволит вам продолжать чтение из буфера приема и предотвратит отправку RST.
Вы также можете использовать этот метод для имитации lingering close, аналогичной той, которая предоставляется модулем ngx_http_core_module для протоколов, которым нужно такое поведение. Вот пример:
local LINGERING_TIME = 30 -- 30 секунд
local LINGERING_TIMEOUT = 5000 -- 5 секунд
local ok, err = sock:shutdown("send")
if not ok then
ngx.log(ngx.ERR, "не удалось закрыть: ", 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
синтаксис: ok, err = reqsock:peek(size)
контекст: preread_by_lua*
Подсматривает в буфер preread, который содержит данные downstream, отправленные клиентом, не потребляя их. То есть данные, возвращаемые этим API, все еще будут переданы upstream на следующих фазах.
Эта функция принимает один обязательный аргумент, size, который представляет собой количество байт для подсматривания.
Повторные вызовы этой функции всегда возвращают данные с начала буфера preread.
Обратите внимание, что фаза preread происходит после TLS-рукопожатия. Если сервер потока был настроен с включенным TLS, возвращаемые данные будут в открытом виде.
Если в буфере preread нет запрашиваемого количества данных, текущая Lua-нить будет
приостановлена до тех пор, пока не станут доступны дополнительные данные, не будет превышен preread_buffer_size
или не истечет preread_timeout.
Успешные вызовы всегда возвращают запрашиваемое количество данных, то есть не будет возвращено частичных
данных.
Когда preread_buffer_size
будет превышен, текущая сессия потока будет немедленно завершена с
кодом состояния сессии session status code 400
ядром модуля потока, с сообщением об ошибке "preread buffer full", которое будет напечатано в журнале ошибок.
Когда preread_timeout будет превышен,
текущая сессия потока будет немедленно завершена с
кодом состояния сессии session status code 200
ядром модуля потока.
В обоих случаях дальнейшая обработка сессии невозможна (кроме log_by_lua*). Соединение будет автоматически закрыто
ядром модуля потока.
Обратите внимание, что этот API не может быть использован, если произошло потребление данных клиента. Например, после вызова
reqsock:receive. Если такая попытка была сделана, будет выброшена ошибка Lua "attempt to peek on a consumed socket".
Потребление данных клиента после вызова этого API разрешено и безопасно.
Вот пример использования этого API:
local sock = assert(ngx.req.socket())
local data = assert(sock:peek(1)) -- подсматриваем первый 1 байт, который содержит длину
data = string.byte(data)
data = assert(sock:peek(data + 1)) -- подсматриваем длину + байт размера
local payload = data:sub(2) -- обрезаем байт длины, чтобы получить фактический полезный груз
ngx.log(ngx.INFO, "полезный груз: ", payload)
Этот API был впервые введен в релизе v0.0.6.
- ngx.print
- ngx.say
- ngx.log
-
Этот вызов в настоящее время игнорирует аргумент
waitи всегда ждет, пока все ожидающие выходные данные полностью не будут сброшены (в системные сокеты отправки). * 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.subsystemВсегда принимает строковое значение Lua
"stream"в этом модуле. * 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
Последняя версия этого модуля совместима со следующими версиями Nginx:
- 1.29.x (последнее тестирование: 1.29.2)
- 1.27.x (последнее тестирование: 1.27.1)
- 1.25.x (последнее тестирование: 1.25.1)
- 1.21.x (последнее тестирование: 1.21.4)
- 1.19.x (последнее тестирование: 1.19.3)
- 1.17.x (последнее тестирование: 1.17.8)
- 1.15.x (последнее тестирование: 1.15.8)
- 1.13.x (последнее тестирование: 1.13.6)
Ядра Nginx старше 1.13.6 (исключительно) не тестировались и могут работать или не работать. Используйте на свой страх и риск!
Укажите системе сборки nginx, где найти LuaJIT 2.1:
export LUAJIT_LIB=/path/to/luajit/lib export LUAJIT_INC=/path/to/luajit/include/luajit-2.1
Здесь мы предполагаем, что Nginx будет установлен в /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
Репозиторий кода
Репозиторий кода этого проекта размещен на GitHub по адресу openresty/stream-lua-nginx-module.
См. также
GitHub
Вы можете найти дополнительные советы по конфигурации и документацию для этого модуля в репозитории GitHub для nginx-module-stream-lua.