Prometheus is a widely adopted open-source monitoring system that collects time-series metrics by scraping HTTP endpoints. Nginx does not expose Prometheus-format metrics natively, but the official nginx-prometheus-exporter bridges the gap by reading Nginx’s built-in stub status page and converting it into a format Prometheus understands. This tutorial shows how to enable the stub status module in Nginx on RHEL 8, run the exporter as a managed systemd service, open the required port with firewalld, and confirm Prometheus is collecting the key Nginx metrics.

Prerequisites

  • RHEL 8 server with Nginx installed and running
  • Prometheus instance (can be on the same host or a separate server) already configured
  • Root or sudo access
  • Internet access to download the exporter binary, or the binary pre-downloaded

Step 1 — Enable the Nginx Stub Status Endpoint

The ngx_http_stub_status_module is compiled into the RHEL 8 Nginx package by default. Enable it by adding a location block that serves the status page only to localhost to avoid public exposure.

sudo tee /etc/nginx/conf.d/stub_status.conf > /dev/null <<'EOF'
server {
    listen 127.0.0.1:8080;
    server_name localhost;

    location /nginx_status {
        stub_status;
        allow 127.0.0.1;
        deny  all;
    }
}
EOF

sudo nginx -t && sudo systemctl reload nginx

# Verify the endpoint responds
curl http://127.0.0.1:8080/nginx_status

The output should show active connections, accepted/handled requests, reading/writing/waiting counts. This raw data is what the exporter will translate into Prometheus metrics.

Step 2 — Download the nginx-prometheus-exporter Binary

Download the latest release of the nginx-prometheus-exporter from the official GitHub releases page. Replace the version number with the current release if a newer one is available.

EXPORTER_VERSION="1.3.0"
cd /tmp

curl -LO "https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v${EXPORTER_VERSION}/nginx-prometheus-exporter_${EXPORTER_VERSION}_linux_amd64.tar.gz"

tar -xzf nginx-prometheus-exporter_${EXPORTER_VERSION}_linux_amd64.tar.gz
sudo mv nginx-prometheus-exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/nginx-prometheus-exporter

# Confirm it runs
nginx-prometheus-exporter --version

Step 3 — Create a systemd Service Unit

Run the exporter under a dedicated unprivileged system account and manage it with systemd so it starts automatically after reboots and restarts on failure.

sudo useradd --system --no-create-home --shell /sbin/nologin nginx-exporter

sudo tee /etc/systemd/system/nginx-exporter.service > /dev/null <<'EOF'
[Unit]
Description=Nginx Prometheus Exporter
After=network.target nginx.service
Requires=nginx.service

[Service]
User=nginx-exporter
Group=nginx-exporter
ExecStart=/usr/local/bin/nginx-prometheus-exporter 
  -nginx.scrape-uri=http://127.0.0.1:8080/nginx_status 
  -web.listen-address=:9113 
  -web.telemetry-path=/metrics
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now nginx-exporter
sudo systemctl status nginx-exporter

Step 4 — Open Port 9113 with firewalld

Allow Prometheus to reach the exporter’s metrics endpoint from the Prometheus server. If Prometheus runs on the same host, restrict the rule to localhost only.

# Allow from a specific Prometheus server IP (replace with your IP)
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="10.0.0.5/32" port port="9113" protocol="tcp" accept'
sudo firewall-cmd --reload

# Verify the metrics endpoint is reachable
curl http://localhost:9113/metrics | grep nginx_

You should see lines beginning with nginx_connections_active, nginx_connections_reading, nginx_http_requests_total, and several others.

Step 5 — Add the Exporter as a Prometheus Scrape Target

Edit the Prometheus configuration file to add the Nginx exporter as a scrape target. The default scrape interval of 15 seconds is suitable for most workloads.

# On your Prometheus host, edit /etc/prometheus/prometheus.yml
# Add the following under the scrape_configs section:

scrape_configs:
  - job_name: 'nginx'
    scrape_interval: 15s
    static_configs:
      - targets: ['your-nginx-server-ip:9113']
        labels:
          instance: 'web-01'

# Reload Prometheus (if running as systemd service)
sudo systemctl reload prometheus

# Or send SIGHUP to the Prometheus process
sudo kill -HUP $(pgrep prometheus)

Step 6 — Verify Key Metrics in Prometheus

Open the Prometheus web UI or run instant queries with curl against the Prometheus HTTP API to confirm the Nginx metrics are being ingested.

# Query active connections
curl -s 'http://localhost:9090/api/v1/query?query=nginx_connections_active' | python3 -m json.tool

# Query total HTTP requests (rate over 5 minutes)
curl -s 'http://localhost:9090/api/v1/query?query=rate(nginx_http_requests_total[5m])' | python3 -m json.tool

# Key metrics available:
# nginx_connections_active      — currently active client connections
# nginx_connections_accepted    — total accepted connections
# nginx_connections_handled     — total handled connections
# nginx_connections_waiting     — keep-alive connections waiting for a request
# nginx_http_requests_total     — total client requests processed
# nginx_up                      — 1 if the exporter can reach Nginx stub_status, 0 otherwise

Conclusion

The Nginx stub status endpoint is now active on localhost, the nginx-prometheus-exporter is running as a hardened systemd service, and Prometheus is scraping and storing the key Nginx connection and request metrics. From here you can build Grafana dashboards using nginx_connections_active and nginx_http_requests_total to visualise traffic patterns, set alert rules on connection saturation, and correlate Nginx performance with application-level metrics.

Next steps: How to Harden Nginx: Security Headers, TLS 1.3 and OCSP Stapling on RHEL 8, How to Configure Nginx WebSocket Proxying on RHEL 8, and How to Set Up a LAMP Stack on RHEL 8.