CubeAPM
CubeAPM CubeAPM

What Are the Best Open Source Nginx Monitoring Tools in 2026

What Are the Best Open Source Nginx Monitoring Tools in 2026

Table of Contents

Nginx is the most widely deployed reverse proxy and web server in production infrastructure, but it does not come with built-in dashboards or alerting. Monitoring it effectively requires connecting two native signal sources to an external platform: the ngx_http_stub_status_module for real-time connection state metrics, and access logs for per-request latency, status code distribution, and upstream response time. Neither is particularly informative on its own. Connection state tells you nginx is saturated but not why. Access logs tell you a specific request was slow but not whether it is a pattern or an isolated event.

Effective Nginx monitoring requires combining both signal sources, correlating them with infrastructure metrics (CPU, memory, network), and ideally correlating request-level signals with distributed traces from the upstream application. The open source tools in this guide cover the full range of approaches, from lightweight single-node setups to full-stack correlation across nginx, upstream services, and infrastructure.

Key Takeaways

  • ngx_http_stub_status_module is not built by default in nginx open source; it requires –with-http_stub_status_module at compile time. Verify with nginx -V 2>&1 | grep -o with-http_stub_status_module.
  • The stub_status module provides only seven connection-state counters; per-request latency and status code visibility requires access log analysis.
  • CPU throttling and high Writing / Active connections ratio are the most actionable early warning signals from stub_status data.
  • nginx-prometheus-exporter v1.5.1 is the current stable release (github.com/nginx/nginx-prometheus-exporter); the repo moved from nginxinc to the nginx organization. Requires nginx 0.1.18 or newer.
  • The OTel Collector nginxreceiver covers the same stub_status metrics as nginx-prometheus-exporter and integrates them into a unified OTel pipeline without a separate exporter process.
  • Grafana, Loki, Tempo, and Mimir are all AGPLv3 (source: grafana.com/licensing).
  • GoAccess v1.10.2 is the current stable release (source: goaccess.io/download); licensed under MIT; the default WebSocket port for real-time HTML output is 7890.
  • The Docker daemon Prometheus endpoint on port 9323 still requires “experimental”: true in daemon.json alongside “metrics-addr”.

What to Monitor in Nginx

1. stub_status Metrics

The ngx_http_stub_status_module is the primary source of real-time nginx metrics. It is not built by default in nginx open source and requires the –with-http_stub_status_module configuration parameter at compile time. Verify it is compiled in with:

nginx -V 2>&1 | grep -o with-http_stub_status_module

If it is available, enable it by adding a status endpoint to your nginx configuration. Restrict access to localhost only:

server {

    listen 127.0.0.1:8080;

    location /stub_status {

        stub_status;

        allow 127.0.0.1;

        deny all;

    }

}

The status page at http://127.0.0.1:8080/stub_status outputs:

Active connections: 291

server accepts handled requests

16630948 16630948 31070465

Reading: 6 Writing: 179 Waiting: 106

All stub_status metrics (from nginx.org/en/docs/http/ngx_http_stub_status_module.html):

MetricDescription
Active connectionsCurrent number of active client connections including those in Waiting state
acceptsTotal accepted client connections since nginx started
handledTotal handled connections. Normally equals accepts unless resource limits were hit
requestsTotal client requests
ReadingConnections where nginx is reading the request header
WritingConnections where nginx is writing a response back to the client
WaitingIdle keepalive connections waiting for a request

Key derived metrics to alert on:

SignalCalculationAlert condition
Active connection saturationActive connections vs worker_connections * worker_processes> 80% of max
Request raterate(requests[5m])Sudden drop or spike vs baseline
Dropped connectionsaccepts – handledAny value > 0 indicates dropped connections
Writing ratioWriting / Active connectionsPersistently high ratio indicates slow upstream

2. Access Log Metrics

The stub_status module tells you about connection state. It tells you nothing about individual requests: which URLs are slow, which status codes are being returned, or how long upstream services are taking to respond. Access logs fill this gap.

Configure nginx to log the variables needed for latency analysis. This log format is from the official nginx.org documentation:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '

                '$status $body_bytes_sent "$http_referer" '

                '"$http_user_agent" "$http_x_forwarded_for" '

                '"$bytes_sent" "$request_length" "$request_time" '

                '"$gzip_ratio" $server_protocol';

access_log /var/log/nginx/access.log main;

Key log variables for performance analysis:

VariableDescription
$request_timeTime in seconds from the first byte of client request to the last byte of response sent
$upstream_response_timeTime in seconds nginx waited for the upstream server to respond
$statusHTTP response status code
$body_bytes_sentBytes sent to the client, not counting the response headers
$bytes_sentTotal bytes sent to the client
$upstream_addrIP address and port of the upstream server

The difference between $request_time and $upstream_response_time reveals where latency is introduced: in nginx itself (TLS overhead, connection setup), in the network path to the upstream, or in the upstream application.

3. Error Log Monitoring

Nginx writes worker errors, upstream connection failures, SSL handshake failures, and resource limit errors to the error log. For production monitoring, ship the error log alongside access logs and alert on:

  • upstream timed out messages (upstream is too slow)
  • connect() failed messages (upstream is unreachable)
  • worker_connections are not enough messages (connection pool exhaustion)
  • too many open files messages (OS file descriptor limit reached)

Best Open Source Nginx Monitoring Tools

1. CubeAPM

cubeapm

CubeAPM is a self-hosted full-stack observability platform that covers all three nginx signal types (stub_status metrics, access log ingestion, and upstream service distributed traces) in one deployment. It is OpenTelemetry-native, so nginx metrics and logs are collected via the OTel Collector and sent to CubeAPM.

Key features for nginx monitoring

  • Collects stub_status metrics via the OTel Collector nginx receiver
  • Access log ingestion via OTel Collector filelog receiver with field extraction for $request_time, $upstream_response_time, $status, and $bytes_sent
  • Error log ingestion with pattern-based alerting on upstream timeout and connection failure messages
  • Distributed traces from upstream applications correlated with nginx access log entries via request ID
  • Infrastructure metrics (CPU, memory, network, disk) correlated with nginx connection state in the same interface
  • Flat $0.15/GB pricing with no per-instance, per-host, or per-user fees
  • Telemetry never leaves your infrastructure

Best for: Teams running nginx as a reverse proxy in front of instrumented application services who want nginx metrics, access logs, upstream traces, and infrastructure metrics correlated in one self-hosted platform.

Limitations: Self-hosted deployment required. Requires at least one engineer comfortable with Helm or Docker Compose.

2. Prometheus with nginx-prometheus-exporter

The official nginx-prometheus-exporter is maintained by NGINX at F5 (github.com/nginx/nginx-prometheus-exporter). It scrapes the stub_status endpoint on nginx open source (or the full NGINX Plus API for NGINX Plus) and exposes all metrics in Prometheus format on port 9113. The current stable release is v1.5.1, requiring nginx 0.1.18 or newer.

Enable stub_status as shown in the configuration above, then run the exporter:

nginx-prometheus-exporter \

  --nginx.scrape-uri=http://127.0.0.1:8080/stub_status \

  --web.listen-address=:9113

Or via Docker:

docker run -p 9113:9113 nginx/nginx-prometheus-exporter:1.5.1 \

  --nginx.scrape-uri=http://host.docker.internal:8080/stub_status

Add the scrape target to Prometheus (current stable: v3.11.2, April 2026):

scrape_configs:

  - job_name: 'nginx'

    static_configs:

      - targets: ['localhost:9113']

    scrape_interval: 15s

Prometheus metrics emitted by nginx-prometheus-exporter (from github.com/nginx/nginx-prometheus-exporter):

MetricTypeDescription
nginx_connections_activegaugeActive client connections
nginx_connections_acceptedcounterAccepted connections total
nginx_connections_handledcounterHandled connections total
nginx_http_requests_totalcounterTotal HTTP requests
nginx_connections_readinggaugeConnections in Reading state
nginx_connections_writinggaugeConnections in Writing state
nginx_connections_waitinggaugeConnections in Waiting (keepalive idle) state
nginx_upgaugeWhether the nginx scrape succeeded (1 = up, 0 = down)

Key PromQL alert rules:

groups:

  - name: nginx

    rules:

      - alert: NginxDown

        expr: nginx_up == 0

        for: 1m

        labels:

          severity: critical

      - alert: NginxHighDroppedConnections

        expr: rate(nginx_connections_accepted[5m]) -

              rate(nginx_connections_handled[5m]) > 0

        for: 2m

        labels:

          severity: warning

      - alert: NginxHighActiveConnections

        expr: nginx_connections_active > 500

        for: 5m

        labels:

          severity: warning

The nginx-prometheus-exporter repository includes an official Grafana dashboard JSON at grafana/dashboard.json in the repo, providing a ready-made visualization for all exported metrics.

Best for: Teams already running Prometheus and Alertmanager who want to add nginx monitoring alongside existing infrastructure and application metrics without introducing a new platform.

Limitations: Only covers stub_status metrics. Does not cover access log analysis or distributed tracing. Per-request latency visibility requires a separate log processing pipeline.

3. Grafana with Loki for Access Log Analysis

Grafana (AGPLv3) with Loki (AGPLv3) for log ingestion and Prometheus for metrics provides a complete open-source nginx monitoring stack covering both stub_status metrics (via nginx-prometheus-exporter) and per-request log analysis (via Promtail or the OTel Collector filelog receiver).

Loki access log ingestion via Promtail:

# promtail-config.yaml

scrape_configs:

  - job_name: nginx

    static_configs:

      - targets:

          - localhost

        labels:

          job: nginx

          __path__: /var/log/nginx/access.log

    pipeline_stages:

      - regex:

          expression: '^(?P<remote_addr>\S+) - \S+ \[.*?\] "(?P<method>\S+) (?P<path>\S+) \S+" (?P<status>\d+) \d+ ".*?" ".*?" ".*?" ".*?" "(?P<request_time>[\d.]+)" ".*?"'

      - labels:

          method:

          status:

      - metrics:

          nginx_request_duration_seconds:

            type: Histogram

            description: "nginx request duration"

            source: request_time

            config:

              buckets: [0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0]

Grafana LogQL queries for nginx access log analysis:

# Request rate by status code

sum(rate({job="nginx"}[5m])) by (status)

# 5xx error rate

sum(rate({job="nginx", status=~"5.."}[5m]))

Best for: Teams already running the Grafana stack (Loki, Prometheus, Grafana) who want unified nginx metrics and log analysis in their existing dashboards.

Limitations: Grafana, Loki, Tempo, and Mimir are all AGPLv3 (source: grafana.com/licensing). Building the log parsing pipeline requires upfront configuration work. No distributed tracing correlation without adding Tempo.

4. OpenTelemetry Collector with nginx Receiver

The OTel Collector Contrib distribution includes an nginxreceiver that scrapes the stub_status endpoint and emits metrics as OTel metric data points. This is the recommended approach for teams standardizing on OpenTelemetry, as it avoids running a separate nginx-prometheus-exporter process and integrates nginx metrics into the same OTel pipeline as all other application and infrastructure telemetry.

OTel Collector config for nginx:

receivers:

  nginx:

    endpoint: "http://127.0.0.1:8080/stub_status"

    collection_interval: 15s

  filelog/nginx_access:

    include:

      - /var/log/nginx/access.log

    operators:

      - type: regex_parser

        regex: '^(?P<remote_addr>\S+) - \S+ \[(?P<time>[^\]]+)\] "(?P<method>\S+) (?P<uri>\S+) \S+" (?P<status>\d+) (?P<bytes>\d+) ".*?" ".*?" ".*?" ".*?" "(?P<request_time>[^"]+)"'

        timestamp:

          parse_from: attributes.time

          layout: "02/Jan/2006:15:04:05 -0700"

  filelog/nginx_error:

    include:

      - /var/log/nginx/error.log

    operators:

      - type: severity_parser

        parse_from: body

processors:

  batch:

    timeout: 10s

  resourcedetection:

    detectors: [env, system]

exporters:

  otlp:

    endpoint: "your-cubeapm-or-other-backend:4317"

    tls:

      insecure: true

service:

  pipelines:

    metrics:

      receivers: [nginx]

      processors: [resourcedetection, batch]

      exporters: [otlp]

    logs:

      receivers: [filelog/nginx_access, filelog/nginx_error]

      processors: [resourcedetection, batch]

      exporters: [otlp]

Metrics emitted by the OTel Collector nginx receiver:

MetricTypeDescription
nginx.connections_acceptedsumTotal accepted connections
nginx.connections_handledsumTotal handled connections
nginx.connections_currentgaugeCurrent connections by state (active, reading, writing, waiting)
nginx.requestssumTotal HTTP requests processed

Best for: Teams already using the OTel Collector as their telemetry pipeline who want nginx metrics and logs in the same OTel stream as application traces and infrastructure metrics.

Limitations: The nginx receiver covers the same stub_status metrics as nginx-prometheus-exporter, not per-request metrics. Access log parsing requires additional filelog receiver configuration.

5. GoAccess

GoAccess is a real-time web log analyzer and interactive terminal dashboard for nginx (and Apache) access logs. It parses access logs directly and produces real-time HTML dashboards and terminal-based reports without requiring a metrics backend, database, or agent. The current stable release is v1.10.2 (source: goaccess.io/download).

Key features

  • Real-time access log analysis: request rate, status code distribution, top requested URLs, bandwidth usage, top IP addresses, browser and OS breakdown
  • Interactive terminal dashboard: live-updating view of all metrics directly in the terminal
  • HTML report generation: produces self-contained HTML reports with real-time WebSocket updates via an embedded server on port 7890 by default
  • WebSocket authentication: JWT-based WebSocket authentication (local and external verification)
  • Nearly all web log format support: handles nginx combined, common, and custom log formats with user-defined format strings
  • Licensed under MIT
  • Available from goaccess.io or package managers: apt install goaccess (note: package managers may ship older versions; goaccess.io/download provides the current source)

Basic usage for real-time nginx access log monitoring:

# Real-time terminal dashboard

goaccess /var/log/nginx/access.log --log-format=COMBINED

# Real-time HTML dashboard with WebSocket updates

goaccess /var/log/nginx/access.log \

  --log-format=COMBINED \

  --real-time-html \

  --port=7890 \

  -o /var/www/html/report.html &

Open the HTML report in a browser for a live-updating dashboard. Ensure port 7890 is open in your firewall when using real-time HTML output.

Best for: Developers and ops teams who need fast, no-dependency nginx access log analysis without setting up a metrics backend. Useful as a diagnostic tool during incidents, or as a lightweight standalone dashboard for small deployments.

Limitations: No metrics storage or alerting. No correlation with infrastructure metrics or distributed traces. No stub_status metrics (log analysis only). Better suited as a diagnostic tool than a production monitoring platform.

Comparison at a Glance

Toolstub_status MetricsAccess Log AnalysisAlertsSelf-hostedLicense
CubeAPMYes (OTel receiver)Yes (OTel filelog)YesYes (required)Proprietary (self-hosted)
Prometheus + exporterYes (v1.5.1)NoYes (Alertmanager)YesApache 2.0
Grafana + LokiYes (with exporter)Yes (Loki/LogQL)Yes (Grafana)YesAGPLv3
OTel CollectorYes (nginx receiver)Yes (filelog receiver)Via backendYesApache 2.0
GoAccessNoYes (log analysis)NoYesMIT

Monitor Your Nginx with CubeAPM

CubeAPM gives nginx teams all three monitoring layers in one self-hosted platform: stub_status connection state metrics, access log request analysis with per-URL latency and error rate breakdowns, and distributed traces from upstream application services.

When an alert fires on a spike in nginx 502 errors, you can navigate from the access log entries directly to the distributed traces of the requests that returned 502, see which upstream service is failing, and correlate the timing with any infrastructure metric changes (CPU spike, disk saturation, network drop) that may have triggered the cascade. All signals are in one interface with no context switching.

At $0.15/GB with no per-instance, per-host, or per-user fees, monitoring any number of nginx instances costs only what telemetry volume you actually ingest.

Summary

Effective nginx monitoring requires both stub_status metrics for connection state and access log analysis for per-request visibility. The tools in this guide cover the full range of approaches.

Monitoring areaPrimary sourceKey signal
Connection statengx_http_stub_status_moduleActive, Reading, Writing, Waiting, dropped connections
Request latencynginx access log $request_timep95/p99 latency, upstream response time
Status code distributionnginx access log $status5xx rate, 4xx rate trends
Upstream healthaccess log $upstream_response_timeLatency per upstream, timeout rate
Error eventsnginx error logUpstream timeouts, connection failures, worker exhaustion
Infrastructure pressureHost CPU, network, memoryCorrelation with nginx saturation events

Disclaimer: All nginx configuration parameters and stub_status metric names sourced from the official nginx.org documentation at nginx.org/en/docs/http/ngx_http_stub_status_module.html, verified June 2026. ngx_http_stub_status_module is not built by default in nginx open source; requires –with-http_stub_status_module at compile time (source: nginx.org). nginx-prometheus-exporter v1.5.1 is the current stable release, requiring nginx 0.1.18 or newer, maintained at github.com/nginx/nginx-prometheus-exporter (source: github.com/nginx/nginx-prometheus-exporter/releases/tag/v1.5.1). Prometheus v3.11.2 current stable (April 13, 2026). OTel Collector nginx receiver documented at github.com/open-telemetry/opentelemetry-collector-contrib. GoAccess v1.10.2 is the current stable release (source: goaccess.io/download and github.com/allinurl/goaccess); licensed under MIT; default WebSocket port is 7890 (source: goaccess.io/man). Grafana, Loki, Tempo, and Mimir are all AGPLv3 (source: grafana.com/licensing). CubeAPM: $0.15/GB, no per-instance or per-host fees.

Also read:

Best Database Monitoring Tools for TimescaleDB in 2026

Best ClickHouse Monitoring Tools in 2026

Observability for Go Applications: Logs, Metrics, and Traces

×
×