Brand logo
HomeLLMsData EngineeringAI ApplicationsPolicy & ComplianceOpen SourceGeneral
  1. Home
  2. /
  3. opensource
  4. /
  5. categorica-nginx-plugin-prometheus-metrics

AIdataNewsGlobal OpenSource Review: Categorica's nginx-stats-prometheus Puts Prometheus Metrics Inside NGINX, Not In A Sidecar

An NGINX worker that answers a scrape on its own listener is a different engineering posture from running a second HTTP service beside it. Today, Categorica has released nginx-stats-prometheus as open-source software, and the design goal is deliberately narrow: collect statistics without spawning a separate exporter process. For teams whose observability path already runs NGINX in front of services, Prometheus as the scrape layer and Grafana as the visualization surface, the release removes one moving part instead of adding one.

Design premise: why the metrics endpoint should not be a web server

Before this module existed, there was effectively one mainstream option for collecting NGINX statistics and metrics: NGINX Prometheus Exporter, a fully featured Prometheus exporter. Categorica's objection was architectural rather than functional — the question raised in the write-up is simply why the metrics endpoint must run its own web-server.

In production terms, that is not a blocker. The exporter can be deployed as a systemd service, and therefore as a regular binary, but NGINX Prometheus Exporter is more commonly run through Docker side-car containers. That side-car pattern adds complexity the maintainers did not consider necessary, and it reintroduces the recursion problem of monitoring: metrics collection itself evades metrics collection, in the manner of “who watches the watchmen”.

The ideological indignation did not survive the free evenings and weekends available to the project. The resulting NGINX plugin became the team's preferred statistics-collection mechanism, and As of today it is published for anyone to build and audit.

At a glance: what the release ships

  • Module identity: nginx-stats-prometheus, published by Categorica; further details sit in the Github repository's README.md.
  • Delivery model: a compiled NGINX module loaded via load_module, serving a Prometheus-compatible route from the NGINX process itself.
  • Licence: MIT, with pull requests accepted under a human-review condition.
  • Toolchain floor: NGINX sources, a C99 compiler such as Clang, PCRE, OpenSSL and zlib headers, and a Unix-like build environment.
  • Hard caps to plan around: 512 server/upstream directives, prefixes longer than 255 characters ignored, 1 megabyte of default shared memory for statistics.

Before you build: prerequisites as a checklist

Command-line comfort is assumed. A basic understanding of the GNU “configure, make, make install” dance is useful, though not strictly necessary. Building NGINX from source is recommended so the required features are compiled in, because a package manager's build of NGINX may differ from the project's; it is still not mandatory.

  • Even when you are not building NGINX from source, the NGINX sources are still needed to compile the module — the supplied Makefile can perform this step.
  • If NGINX is not being built from source, it must have been compiled with --with-compat and --with-http_stub_status_module.
  • A C99 compiler, such as Clang, is required.
  • The PCRE, OpenSSL, and zlib libraries and headers must be present.
  • All steps assume a Unix-like environment.

Step 1 — Building NGINX

Skip this step if an appropriate NGINX version is already installed. In a terminal, use:

cd path-to-nginx-source;
# we'll use the path to the NGINX source whilst building the plugin.
export NGINX_SRC=`pwd`;
./configure --with-compat --with-http_stub_status_module;
make -j;
sudo make install;

This builds and installs NGINX, typically with the /usr/local prefix. For more details about building NGINX, consult their documentation.

Step 2 — Building the plugin

If an appropriate NGINX version is already installed, the supplied Makefile determines its version by invoking nginx -v, then downloads the NGINX sources needed to build the module.

If that behavior is not wanted, set the path to the NGINX sources with the environment variable NGINX_SRC; this skips the version check and source download.

Afterward, build the plugin with:

make module
sudo make install

This builds the plugin and installs it to the correct plugin location. More information can be found on the Github repository's README.md.

Case study — exposing and verifying the endpoint on a local host

After building the plugin, configuration must describe the route where statistics should be exposed.

load_module modules/ngx_http_stats_prom_module.so;
http {
# Optional: set shared memory size (default 1m)
# prometheus_metrics_shm_size 2m;
server {
# standard NGINX server directives apply here
listen 9100;
location /metrics {
prometheus_metrics;
}
}
}

This configuration exports statistics suitable for Prometheus ingestion at http://hostname:9100/metrics. Assuming the NGINX instance runs locally, the endpoint can be queried with curl:

curl http://localhost:9100/metrics

Sample response:

# HELP nginx_up Whether the nginx process is up
# TYPE nginx_up gauge
nginx_up 1
# HELP nginx_process_pid PID of the worker process (serving metrics)
# TYPE nginx_process_pid gauge
nginx_process_pid 2985885
# HELP nginx_http_requests_total Total number of HTTP requests
# TYPE nginx_http_requests_total counter
nginx_http_requests_total 434488
# HELP nginx_http_responses_total HTTP responses by status class
# TYPE nginx_http_responses_total counter
nginx_http_responses_total{status="1xx"} 0
nginx_http_responses_total{status="2xx"} 42598
nginx_http_responses_total{status="3xx"} 771
nginx_http_responses_total{status="4xx"} 77
nginx_http_responses_total{status="5xx"} 1
# etc.

Read as a verification procedure, this output tells an engineer three checkable things: the scrape surface is live inside the web server itself (nginx_up reporting 1), the metrics are attached to a specific worker (nginx_process_pid showing 2985885), and the traffic shape is already aggregated by status class — 434488 requests with 42598, 771, 77 and 1 in the 2xx, 3xx, 4xx and 5xx buckets, and 0 in the 1xx bucket. The deployment limits are equally visible: the commented prometheus_metrics_shm_size line defaults to 1m and shows 2m as the tuning knob, while port 9100 has to be reserved on the host.

Exported statistics: process-level metrics

Once the process is running, NGINX metrics should be visible on the route specified in the configuration. Once started, the available metrics are:

MetricTypeLabels
nginx_upgauge
nginx_process_pidgauge
nginx_http_requests_totalcounter
nginx_http_responses_totalcounterstatus (1xx – 5xx)
nginx_http_requests_by_method_totalcountermethod (GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH, other)
nginx_http_request_bytes_totalcounter
nginx_http_response_bytes_totalcounter
nginx_http_version_totalcounterversion (1.0, 1.1, 2.0, 3.0)
nginx_http_request_duration_secondshistogram(0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10)
nginx_connections_activegauge
nginx_connections_readinggauge
nginx_connections_writinggauge
nginx_connections_waitinggauge
nginx_connections_accepted_totalcounter
nginx_connections_handled_totalcounter

These are available as soon as the process launches, and are measured from process start.

Exported statistics: per-server and per-upstream metrics

In addition, basic metrics exist for each server or upstream directive defined in nginx.conf. These appear after the first received request on that prefix.

MetricTypeLabels
<prefix>_requests_totalcounterserver / upstream
<prefix>_response_totalcounterserver / upstream, status (1xx – 5xx)
<prefix>_request_bytes_totalcounterserver / upstream
<prefix>_response_bytes_totalcounterserver / upstream

Comparison: in-process module versus the standalone exporter

Dimensionnginx-stats-prometheusnginx-prometheus-exporter
Process modelRuns inside NGINX; no separate exporter processSeparate endpoint that runs its own web-server
Typical deploymentCompiled module loaded with load_modulesystemd service / regular binary, or more commonly Docker side-car containers
Metric coverageSignificantly fewer statistics are collectedFully featured set
Version couplingTied to the NGINX version it is built against; updating NGINX typically requires rebuildingNot described as tied to a build
MaturitySignificantly less battle tested; less mature and less usedThe established option to date
LicenceMITNot stated in the source article
SupportNone offered by the maintainersNot stated in the source article

Capacity limits and silent failure modes

At most, 512 server or upstream directives are supported. Prefix lengths greater than 255 characters are ignored. Only 1 megabyte of memory is allocated for statistics. If this is exhausted, statistics collection is silently skipped. This can be configured in NGINX with prometheus_metrics_shm_size, whose default is 1m and which the sample configuration illustrates with a 2m value.

Common misconceptions

  • “It is a drop-in replacement.” It is not a drop-in replacement for nginx-prometheus-exporter; significantly fewer statistics are collected.
  • “Installed from a package manager, so no sources needed.” The NGINX sources are still required to compile the module even when you do not build NGINX yourself.
  • “A package-manager binary will behave identically.” A distribution build may differ; if NGINX is not built from source it must already carry --with-compat and --with-http_stub_status_module.
  • “Per-vhost counters exist from boot.” They appear only after the first received request on that prefix; process-level metrics, by contrast, are measured from process start.
  • “Empty dashboard means zero traffic.” With 512 directives exceeded, a prefix above 255 characters, or the 1 megabyte statistics pool exhausted, collection is silently skipped rather than reported.
  • “Rebuilding is optional.” The plugin is tied to the NGINX version it is built against, so an NGINX update typically forces a rebuild.

Licence, contribution and support boundaries

nginx-stats-prometheus is released under an MIT licence. Pull requests are welcome, with one condition: a human must have at least reviewed the patch-set before submission. On the support side, the maintainers currently offer no support and cannot guarantee help with any issues that may arise from its use — so any adoption decision is effectively an internal ownership decision.

Action recommendations for evaluation

  1. Inventory your scrape topology: if you already run Docker side-car containers purely for metrics, you have the clearest candidate for consolidation.
  2. Confirm the build floor first — C99 compiler (Clang is cited), PCRE, OpenSSL, zlib headers, and a Unix-like environment — before committing engineering time.
  3. Prefer building NGINX from source with --with-compat --with-http_stub_status_module when your distribution build is unknown; otherwise verify both flags are present.
  4. Pin the plugin build to the exact NGINX version and add a rebuild step to your NGINX upgrade runbook.
  5. Validate the endpoint manually with curl http://localhost:9100/metrics before wiring Prometheus scrape config, and check nginx_up, nginx_process_pid and the status-class counters against known traffic.
  6. Size prometheus_metrics_shm_size (default 1m) against your actual number of server/upstream blocks; treat 512 directives and 255-character prefixes as design limits.
  7. Keep a parallel path to nginx-prometheus-exporter for panels that depend on richer coverage, since fewer statistics are collected here.
  8. Because support is explicitly not offered, record an internal owner and a removal plan; MIT permits the fork, but nobody else carries the on-call.

For a reader whose job is to judge whether an open-source project is usable rather than merely interesting, this release is best filed under “narrow, inspectable, and build-dependent”: the value is architectural — one fewer HTTP service between you and your metrics — and the cost is equally architectural, in the form of version pinning, reduced coverage and an absent support channel. If you want to run NGINX without containerisation, are looking to simplify your deployment configuration, or just prefer running statistics collection from a plugin, try nginx-stats-prometheus — then decide, from the verified endpoint output, whether the trade is worth owning.

Brand logo

AI & Data News

Frontier Reporting on Foundation Models & Data Engineering

LLMsData EngineeringAI ApplicationsPolicy & ComplianceOpen SourceGeneralGlobal SaaSManager

© 2026 AI & Data News.

Cookie Notice

We use cookies to improve your experience and analyze website traffic. Read our Privacy Policy to learn more.