ngx_lua_config_module provides the ngx_http_lua_config_module and
ngx_stream_lua_config_module modules. They allow defining key-value
configuration items in Nginx configuration, which can then be retrieved
through the resty.config Lua API or as nginx variables. The legacy
ngx.lua_config C/Lua API remains available for compatibility.
- ngx_lua_config_module
- Name
- Table of Content
- Status
- Synopsis
- Installation
- Conditional syntax
- Directives
- Variables
- Lua API
- Benchmark
- Author
- License
These Nginx modules are currently considered experimental. Issues and PRs are welcome if you encounter any problems.
http {
lua_config server_id my_server_id;
server {
listen 80;
server_name example.com;
# Local configuration overrides parent configuration
lua_config server_id my_server_id_A;
lua_upstream backend {
server 127.0.0.1:8080 weight=5;
server 10.0.0.2:8080 level=1;
keepalive_timeout 60s;
}
location /api {
# Local configuration
lua_config api_version v1.0;
# Access via Nginx variables
add_header X-Env $lua_config_environment;
add_header X-Server-Region $lua_config_server_region;
add_header X-Server-Id $lua_config_server_id; # "my_server_id_A"
add_header X-Api-Version $lua_config_api_version;
content_by_lua_block {
-- Access via Lua API
local lua_config = require "resty.config"
local env = lua_config.get("environment")
local region = lua_config.get("server_region")
local server_id = lua_config.get("server_id") -- "my_server_id_A"
local api_version = lua_config.get("api_version")
ngx.log(ngx.INFO, "Env: ", env, ", Region: ", region, ", Server ID: ", server_id, ", API Version: ", api_version)
-- Access upstream config
local up = lua_config.get_upstream("backend")
if up then
ngx.log(ngx.INFO, "Backend CRC32: ", up.crc32)
end
ngx.say("OK")
}
}
location /another {
# In another location, server_id will be my_server_id_A
# api_version is not defined here, so it will be nil
content_by_lua_block {
local lua_config = require "resty.config"
local server_id = lua_config.get("server_id")
local api_version = lua_config.get("api_version")
ngx.log(ngx.INFO, "Server ID: ", server_id, ", API Version: ", api_version or "nil")
ngx.say("OK")
}
}
}
}stream {
lua_init_config app_name stream_gateway;
lua_config environment production;
lua_config server_id stream_default;
lua_upstream backend {
server 127.0.0.1:8080 weight=5;
server 10.0.0.2:8080 level=1;
keepalive_timeout 60s;
}
server {
listen 10000;
# Server configuration overrides stream-level configuration
lua_config server_id stream_edge_A;
lua_config peer $remote_addr;
content_by_lua_block {
local lua_config = require "resty.config"
ngx.say("environment=", lua_config.get("environment"))
ngx.say("server_id=", lua_config.get("server_id"))
-- The same item is also available as an nginx variable
ngx.say("peer=", ngx.var.lua_config_peer)
local up = lua_config.get_upstream("backend")
if up then
ngx.say("backend_crc32=", up.crc32)
end
}
}
}To use these modules, configure your Nginx branch with --add-module=/path/to/ngx_lua_config_module.
The same addon registers ngx_http_lua_config_module when HTTP is enabled and
ngx_stream_lua_config_module when Stream is enabled. Enable the nginx Stream
subsystem (for example, with --with-stream) and build with
ngx_stream_lua_module to use the Stream Lua API.
Install lualib/resty/config.lua into the OpenResty Lua library path (normally lualib/resty/config.lua under the OpenResty prefix) to use the FFI API.
To enable named conditions, build ngx_expr_module and this module statically in the same nginx configuration.
The Stream module currently requires a patched ngx_stream_lua_module.
Download ngx_stream_lua_module-expose_request_struct_0.0.18RC2+.patch from
the OpenResty patches directory
and apply it before building OpenResty with ngx_stream_lua_config_module.
This dependency is still required when using the recommended
require "resty.config" FFI API. resty.config obtains an
ngx_stream_lua_request_t * from resty.core.base.get_request() and passes it
to the Stream FFI functions. The module then reads r->session, so the
definition of ngx_stream_lua_request_t must be visible to this external
module.
The patch provides two interfaces:
- It exposes the
ngx_stream_lua_request_tdefinition required by the Stream FFI implementation. - It exports
ngx_stream_lua_get_request(lua_State *L), which is still used by the legacyrequire "ngx.lua_config"compatibility API.
Removing the legacy API would eliminate the second requirement, but it would
not eliminate the FFI request-structure requirement. Do not remove this patch
solely because callers have migrated to resty.config. The HTTP module does
not require this Stream-specific patch.
Conditional syntax is selected at compile time and has the same behavior in both HTTP and Stream:
- With
ngx_expr_module, use namedexprexpressions and placelua_configinsidewhenblocks. HTTP supportshttp,server, andlocationwhencontexts; Stream supportsstreamandserverwhencontexts. Legacyif=andif!=parameters are rejected. - Without
ngx_expr_module,whenis unavailable and legacyif=/if!=parameters remain supported bylua_config.
When a conditional lua_config does not match, the next definition of the same key is evaluated. If no definition matches, that key lookup returns nil.
lua_upstream does not provide conditional-entry syntax. Except for server,
each statement in its block is parsed as a regular key-value item.
Syntax: lua_config key string ... [separator=,];
Default: -
HTTP context: http, server, location, when
Stream context: stream, server, when
Defines a key-value configuration item. The key parameter may only contain
lowercase letters, numbers, and underscores. The string parameters can
contain variables. Multiple string parameters are concatenated using a
separator. The default separator is ,.
Legacy if= matches a non-empty value other than "0"; if!= matches an empty value or "0". These parameters are available only without ngx_expr_module.
HTTP example:
lua_config data_source primary;
expr has_test_arg !is_empty $arg_test;
when has_test_arg {
lua_config set_header $arg_test;
}
lua_config allow_methods GET HEAD POST;
lua_config cache_timeout 300s;Stream example:
stream {
expr has_ssl_protocol !is_empty $ssl_preread_protocol;
when has_ssl_protocol {
lua_config protocol $ssl_preread_protocol;
}
lua_config protocol unknown;
}Syntax: lua_config_hash_max_size number;
Default: lua_config_hash_max_size 512;
HTTP context: http, server, location
Stream context: stream, server
Sets the maximum size of the hash table for storing lua_config key-value pairs.
Syntax: lua_config_hash_bucket_size number;
Default: lua_config_hash_bucket_size 32|64|128;
HTTP context: http, server, location
Stream context: stream, server
Sets the bucket size of the hash table for lua_config items. The default value depends on the processor's cache line size. Details on setting up hash tables are provided in a separate document.
Syntax: lua_upstream name { ... }
Default: -
HTTP context: http, server
Stream context: stream, server
Defines a named upstream configuration block that can be retrieved at request
time via the Lua API. The name may only contain lowercase letters, digits,
and underscores. Duplicate names within the same context are not allowed. A
server-level definition completely overrides a definition with the same name
at the enclosing http or stream level; upstream definitions are not merged.
Inside the block, two types of entries are supported:
Server entries:
server host[:port] [level=N] [weight=N] [down];
host: An IP address (IPv4 or IPv6 in[addr]notation), domain name, or Unix domain socket path prefixed withunix:. Variables are not allowed.port: Optional port number. Defaults to0if omitted.level: Server level, defaults to1.weight: Server weight, defaults to1.down: Marks the server as unavailable.
Config items:
key value; # key-value pair
key: Only lowercase letters, digits, and underscores allowed.value: An arbitrary string, supports variables.- All tokens after
keyare value fragments, except for a trailingseparator=parameter.
HTTP example:
http {
lua_upstream backend {
server 127.0.0.1:8080 level=0 weight=5;
server [::1]:8081 level=1;
server backup.example.com:9090 level=2 down;
keepalive_timeout 60s;
connect_timeout 5s;
}
server {
# This completely overrides the http-level "backend"
lua_upstream backend {
server 10.0.0.1:9090;
}
}
}Stream example:
stream {
lua_upstream backend {
server 127.0.0.1:8080 level=0 weight=5;
server [::1]:8081 level=1;
server backup.example.com:9090 level=2 down;
keepalive_timeout 60s;
connect_timeout 5s;
}
server {
listen 10000;
# This completely overrides the stream-level "backend"
lua_upstream backend {
server 10.0.0.1:9090;
}
}
}Syntax: lua_init_config key string ... [separator=,];
Default: -
HTTP context: http
Stream context: stream
Defines a static key-value configuration item that is available during the
init and init_worker phases, before any request is processed. Unlike
lua_config, this directive does not support variables or conditional
evaluation: values are plain strings. Multiple string parameters are
concatenated using a separator. The default separator is ,. HTTP and Stream
maintain separate init-configuration tables.
Example:
http {
lua_init_config app_name my_application;
lua_init_config version 1.0.0;
lua_init_config allowed_origins http://a.com http://b.com http://c.com;
lua_init_config allowed_methods GET HEAD POST separator=|;
}
stream {
lua_init_config app_name my_stream_application;
lua_init_config protocols tcp udp separator=|;
}Accesses the value of a specific lua_config item by its name. The prefix
variable is registered by both modules and resolves against the current HTTP
request or Stream session.
HTTP example:
lua_config data_source my_data_source;
add_header My-Config-Value $lua_config_data_source;Stream example:
stream {
lua_config data_source my_stream_data_source;
server {
listen 10000;
content_by_lua_block {
ngx.say(ngx.var.lua_config_data_source)
}
}
}The recommended API is loaded with
local lua_config = require "resty.config". It uses LuaJIT FFI, detects the
current subsystem through ngx.config.subsystem, and selects the HTTP or
Stream FFI implementation automatically. Both implementations provide the
same result shapes as the legacy require "ngx.lua_config" API.
Syntax: value = lua_config.get(key)
HTTP context: set_by_lua*, rewrite_by_lua*, access_by_lua*,
content_by_lua*, header_filter_by_lua*, body_filter_by_lua*,
log_by_lua*, balancer_by_lua*
Stream context: preread_by_lua*, content_by_lua*, log_by_lua*,
balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*
Retrieves the value of a specific lua_config item by its key.
key: A string representing the key name of the configuration item to query.- The value of the corresponding configuration item (string type) if found.
nilif the configuration item is not found.
Example:
local lua_config = require "resty.config"
local my_data_source = lua_config.get("data_source")
if my_data_source then
ngx.log(ngx.INFO, "Data source: ", my_data_source)
else
ngx.log(ngx.WARN, "Data source not found!")
endSyntax: result = lua_config.get_upstream(name)
HTTP context: server_rewrite_by_lua*, set_by_lua*,
rewrite_by_lua*, access_by_lua*, precontent_by_lua*,
content_by_lua*, header_filter_by_lua*, body_filter_by_lua*,
log_by_lua*, balancer_by_lua*, proxy_ssl_certificate_by_lua_*,
proxy_ssl_verify_by_lua_*
Stream context: preread_by_lua*, content_by_lua*, log_by_lua*,
balancer_by_lua*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*
Retrieves the upstream configuration defined by lua_upstream for the given name.
name: A string representing the upstream name to look up.- Returns
nilif the upstream is not found. - Returns a table with the following fields:
name(string): The upstream name.servers(array): Each entry is a table with:host(string): The server host.port(number): The server port (0if not specified).level(number): The server level (1if not specified).weight(number): The server weight.(1if not specified).down(boolean): Whether the server is marked down.
- config keys: Each key defined in the block appears as a field. All keys have their resolved string value, with variables evaluated.
crc32(string): A CRC32 checksum (decimal string) computed from the upstream name, all server entries, and all config key-value pairs (keys sorted alphabetically). The checksum changes when any resolved value changes, making it useful for detecting configuration drift.
Example:
local lua_config = require "resty.config"
local up = lua_config.get_upstream("backend")
if not up then
ngx.say("upstream not found")
return
end
ngx.say("name: ", up.name)
ngx.say("crc32: ", up.crc32)
for i, srv in ipairs(up.servers) do
ngx.say("server ", i, ": ", srv.host, ":", srv.port,
" level=", srv.level, " weight=", srv.weight,
" down=", tostring(srv.down))
end
if up.keepalive_timeout then
ngx.say("keepalive_timeout: ", up.keepalive_timeout) -- "60s" (string value)
endSyntax: configs = lua_config.get_init_configs()
HTTP context: any
Stream context: any
Returns a table containing all key-value pairs defined by lua_init_config
directives for the current subsystem. Returns an empty table if no
lua_init_config directives are defined.
Example:
local lua_config = require "resty.config"
local configs = lua_config.get_init_configs()
for k, v in pairs(configs) do
ngx.log(ngx.INFO, k, " = ", v)
endbench/benchmark.t compares the legacy API with resty.config in the same request. It alternates execution order across seven rounds, reports the median nanoseconds per operation, and checks that both paths produce the same checksum.
Run it with Test::Nginx and an optimized OpenResty build:
TEST_NGINX_BINARY=/path/to/nginx prove -v bench/benchmark.tHanada im@hanada.info
This Nginx module is licensed under BSD 2-Clause License.