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.