knyar/nginx-lua-prometheus for Nginx metrics
Prometheus metric library for Nginx written in Lua
At a glance
- What is it?
- knyar/nginx-lua-prometheus is a Lua library for recording Prometheus counters, gauges, and histograms inside Nginx. It fits OpenResty and nginx deployments that need application-specific metrics, but it requires ngx_lua and deliberate control of cardinality and worker synchronization.
- Who is it for?
- Adopt this library when the Nginx deployment already includes ngx_lua and metrics must be defined from Lua configuration. Do not choose it for a stock Nginx server without Lua support or when a complete, prebuilt exporter would better fit the operation.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 41 days ago.
- What is it written in?
- Mainly Lua, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why nginx-lua-prometheus belongs inside Nginx
knyar/nginx-lua-prometheus addresses a specific gap between generic Nginx monitoring and metrics that describe application behavior handled by Lua. Prometheus can pull text-format metrics from an HTTP endpoint, but an Nginx server does not automatically expose arbitrary Lua counters or histograms. This library registers those metric types, stores their values, and renders them for collection.
It is intended for operators and application engineers running an nginx-based server with the `ngx_lua` module. That includes OpenResty and a regular Nginx installation compiled with the relevant Lua module. The README gives `libnginx-mod-http-lua` as an installation example on Debian 10, while directing users to its known issues for later Debian releases.
The library is most useful when the desired data comes from Nginx variables or Lua request logic. The documented example records request totals by server name and HTTP status, request latency by server name, and current connection counts by state. It does not replace a general Prometheus server, and it does not make Nginx itself Prometheus-aware. Nginx must run the Lua module, load the library, update metrics during request processing, and expose a separate endpoint for Prometheus.
How Lua metrics move through shared memory
The initialization API is `require("prometheus").init(*dict_name*, [*options*]])`. According to the README, it should run once from `init_worker_by_lua_block`. The named Nginx shared dictionary stores metric data. The quick start creates a dictionary called `prometheus_metrics` with a 10MB size limit and initializes the library against it.
Metric objects are registered during worker initialization. `prometheus:counter()` returns a counter, `prometheus:gauge()` returns a gauge, and `prometheus:histogram()` returns a histogram. Their label arrays become part of each metric definition. Later request code increments counters, observes latency values, or sets gauges. For example, the documented log phase reads `ngx.var.server_name`, `ngx.var.status`, and `ngx.var.request_time` before recording values.
Counters and histograms can maintain per-worker data. The documented `sync_interval` option controls how often per-worker counters and the key index are synchronized, in seconds. It defaults to 1 and defines the boundary for eventual consistency of counter increments and metric resets or deletions. This is an operational trade-off rather than immediate global consistency.
A separate Nginx server exposes `/metrics`. Calling `prometheus:collect()` renders the registered metrics for Prometheus to pull. Gauges connected to Nginx global state are set immediately before collection in the documented example, so their reported values reflect the state at scrape time. The shared dictionary must be sized for the metric data retained across workers and label combinations.
Installing the library through OpenResty, LuaRocks, or LUA_PATH
There are three documented acquisition routes: the OpenResty package manager, LuaRocks, or a checkout made available through `LUA_PATH`. The repository provides no documented installation command, package version flag, or copy destination, so adding one would go beyond the README.
OpenResty users can obtain the library through `opm`. The README also lists the `knyar/nginx-lua-prometheus` module on LuaRocks. For manual use, the required file is `prometheus.lua`, and it must be available through `LUA_PATH`. If this is the only Lua library in the checkout, the README says `lua_package_path` can point directly at the repository directory.
The following is the documented shared dictionary and module path configuration. Replace the example repository path with the actual checkout path, and ensure the shared dictionary has enough capacity for the metrics you define.
lua_shared_dict prometheus_metrics 10M;
lua_package_path "/path/to/nginx-lua-prometheus/?.lua;;";The shared dictionary is mandatory in this configuration because it backs all metric values. The `;;` entry preserves Nginx's default Lua search path. The README also identifies `prometheus_keys.lua` and `prometheus_resty_counter.lua` as repository files, but it does not document a separate installation step for them.
Registering and updating request metrics
The first real use starts in `init_worker_by_lua_block`. The following configuration initializes the module, registers one counter, one histogram, and one gauge, then records request information from Nginx variables in the log phase.
init_worker_by_lua_block {
prometheus = require("prometheus").init("prometheus_metrics")
metric_requests = prometheus:counter(
"nginx_http_requests_total", "Number of HTTP requests", {"host", "status"})
metric_latency = prometheus:histogram(
"nginx_http_request_duration_seconds", "HTTP request latency", {"host"})
metric_connections = prometheus:gauge(
"nginx_http_connections", "Number of HTTP connections", {"state"})
}
log_by_lua_block {
metric_requests:inc(1, {ngx.var.server_name, ngx.var.status})
metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.server_name})
}The counter stores the server name as `host` and the HTTP status as `status`. The histogram observes `request_time` in seconds, as indicated by the metric name, and labels it with `host`. Registration belongs in worker initialization because the README explicitly says each metric should be registered once from that phase.
The counter increments for each request processed by the log phase. Prometheus expects counters to represent accumulated totals, which fits `inc(1)`. Label values should remain bounded. The README does not document automatic label cleanup rules suitable for every cardinality pattern, so arbitrary values such as unbounded user-controlled paths would require careful review before being used as labels.
Serving /metrics without exposing Nginx state
The README requires a separate server for metric collection and says it must be reachable only from the Prometheus server. Its example listens on port `9145`, permits the private `192.168.0.0/16` range, denies other clients, and limits the metrics route to `/metrics`.
server {
listen 9145;
allow 192.168.0.0/16;
deny all;
location /metrics {
content_by_lua_block {
metric_connections:set(ngx.var.connections_reading, {"reading"})
metric_connections:set(ngx.var.connections_waiting, {"waiting"})
metric_connections:set(ngx.var.connections_writing, {"writing"})
prometheus:collect()
}
}
}After Nginx reloads the configuration, the endpoint is documented as `http://your.nginx:9145/metrics`. A permitted Prometheus client should receive Prometheus text metrics, including the counter and histogram data accumulated by request handlers and the current connection gauge values.
The sample access rule is an example tied to one private network. It does not automatically accommodate a different Prometheus placement, container subnet, proxy, or TLS configuration. Those cases require an explicit access policy rather than copying the sample addresses unchanged. The README also does not document authentication or rollback procedures for the metrics listener.
Consistency, cardinality, and shared-dictionary constraints
The library's worker-oriented storage introduces a consistency boundary. With the default `sync_interval` of 1 second, a scrape can precede synchronization of a counter increment made by another worker. Changing the value increases the possible delay before per-worker counters and the key index become consistent. The README describes this as eventual consistency and includes the option directly in the initialization API:
init_worker_by_lua_block {
prometheus = require("prometheus").init("prometheus_metrics", {sync_interval=3})
}This configuration establishes a three-second synchronization interval. It does not promise that every scrape will be exactly three seconds behind, but it changes the documented boundary for counter visibility, resets, and deletions.
Label cardinality is the other major constraint. A label such as `status` has a naturally limited set in the example, while `host` follows `ngx.var.server_name`. Metric storage grows as label combinations accumulate in the shared dictionary, making the initial 10MB allocation a starting example rather than a universal sizing rule. The README does not state how to calculate exact memory requirements.
Metric naming also affects Prometheus queries and alerts. The library accepts a name and description when registering each metric, while an optional `prefix` can prepend a string during output. Operators therefore need to decide names before deployment because renaming them later can disrupt existing Prometheus queries and recording rules. The README does not document a migration procedure for metric renames.
Maintenance signals and MIT adoption cost
The repository is not archived, and its last push was on 2026-09-11. That is a recent repository activity signal as of the project information available here, but the repository has no GitHub releases. There is therefore no documented release cadence or versioned upgrade sequence to rely on. Consumers also need to account for compatibility with their Nginx or OpenResty and `ngx_lua` environment themselves.
The project is distributed under the MIT License. That supports reuse and modification under the license's conditions, but this review does not provide legal advice. The adoption cost is primarily configuration work: integrating with an Nginx Lua runtime, choosing metric names and labels, sizing shared memory, protecting the scrape endpoint, and checking synchronization behavior after upgrades.
A real alternative for teams that do not want to define metrics in Lua is to use a prebuilt Nginx exporter and keep application instrumentation outside the server configuration. The practical difference is ownership. nginx-lua-prometheus allows metrics to be updated directly from `log_by_lua_block` and other Lua-controlled request paths, while a prebuilt exporter provides a fixed collection surface. The choice depends on whether application-specific instrumentation is necessary and whether the deployment already supports `ngx_lua`.
Editorial conclusion
Adopt this library when the Nginx deployment already includes ngx_lua and metrics must be defined from Lua configuration. Do not choose it for a stock Nginx server without Lua support or when a complete, prebuilt exporter would better fit the operation. Before adoption, verify the `lua_package_path`, shared dictionary capacity, scrape endpoint access controls, label cardinality, and the expected delay imposed by `sync_interval`.
Frequently asked questions
What does knyar/nginx-lua-prometheus require?
It requires an Nginx-based server with the `ngx_lua` module, either OpenResty or a regular Nginx installation with Lua support. The `prometheus.lua` file must also be available through `LUA_PATH`.
How are metrics stored and exposed in knyar/nginx-lua-prometheus?
Metrics are stored in a named Nginx shared dictionary and registered during worker initialization. A separate Nginx location calls `prometheus:collect()` to render them at `/metrics` for Prometheus.
Does knyar/nginx-lua-prometheus support counters, gauges, and histograms?
Yes. The API provides `prometheus:counter()`, `prometheus:gauge()`, and `prometheus:histogram()`, with optional metric descriptions and label names.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/knyar-nginx-lua-prometheus)Was this useful?