How to Monitor Nginx with Prometheus nginx-exporter on RHEL 7
Monitoring your Nginx web server with Prometheus and Grafana gives you real-time visibility into request rates, connection states, error rates, and server performance over time. The Prometheus ecosystem works through a scrape model: an exporter process exposes metrics at an HTTP endpoint in a text format that Prometheus polls at a configurable interval. For Nginx, the official nginx-prometheus-exporter from NGINX Inc. reads data from Nginx’s built-in stub_status module and translates it into Prometheus-compatible metrics. This tutorial covers enabling stub_status, installing and configuring the exporter as a systemd service, configuring Prometheus to scrape it, and importing a Grafana dashboard to visualize the data — all on RHEL 7.
Prerequisites
- RHEL 7 server with root or sudo access.
- Nginx installed and running.
- Prometheus installed (covered briefly in this tutorial) or an existing Prometheus instance that can reach this server.
- Grafana installed (optional, for dashboards) — can be on the same server or remote.
- Internet access to download the nginx-prometheus-exporter binary.
Step 1: Enable the Nginx stub_status Module
The ngx_http_stub_status_module exposes a small status page showing Nginx’s current connection counts and request totals. Verify that your Nginx build includes this module:
nginx -V 2>&1 | grep -o with-http_stub_status_module
If the module is compiled in, you will see with-http_stub_status_module in the output. Most Nginx packages from EPEL and the official Nginx repository include it.
Configure the /nginx_status location in your Nginx configuration. Add it inside an existing server block or create a dedicated server block accessible only from localhost:
server {
listen 127.0.0.1:8080;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
Restricting access to 127.0.0.1 is critical — the status page itself does not contain sensitive secrets, but exposing it publicly wastes bandwidth and reveals traffic patterns. Save the configuration, test, and reload:
sudo nginx -t
sudo systemctl reload nginx
Verify the status page is accessible locally:
curl http://127.0.0.1:8080/nginx_status
You should see output similar to:
Active connections: 4
server accepts handled requests
1024 1024 8192
Reading: 0 Writing: 1 Waiting: 3
Each line describes:
- Active connections: Total open connections including waiting clients.
- accepts / handled / requests: Cumulative totals since Nginx started.
- Reading / Writing / Waiting: Current connection states (headers being read, responses being sent, keep-alive idle).
Step 2: Download the nginx-prometheus-exporter Binary
The official nginx-prometheus-exporter is distributed as a statically compiled Go binary — no runtime dependencies required. Download the latest release for Linux AMD64:
EXPORTER_VERSION="1.3.0"
curl -L "https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v${EXPORTER_VERSION}/nginx-prometheus-exporter_${EXPORTER_VERSION}_linux_amd64.tar.gz"
-o /tmp/nginx-prometheus-exporter.tar.gz
Extract and install the binary:
tar -xzf /tmp/nginx-prometheus-exporter.tar.gz -C /tmp
sudo mv /tmp/nginx-prometheus-exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/nginx-prometheus-exporter
Verify the binary works:
nginx-prometheus-exporter --version
Step 3: Create a Dedicated System User for the Exporter
Running exporters as root is unnecessary and increases your attack surface. Create a dedicated unprivileged system user:
sudo useradd --system --no-create-home --shell /sbin/nologin nginx-exporter
Step 4: Create a systemd Service for the Exporter
Create the systemd unit file at /etc/systemd/system/nginx-prometheus-exporter.service:
sudo tee /etc/systemd/system/nginx-prometheus-exporter.service <<'EOF'
[Unit]
Description=Nginx Prometheus Exporter
Documentation=https://github.com/nginxinc/nginx-prometheus-exporter
After=network.target
[Service]
User=nginx-exporter
Group=nginx-exporter
Type=simple
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=5s
NoNewPrivileges=yes
PrivateTmp=yes
[Install]
WantedBy=multi-user.target
EOF
Key flags explained:
--nginx.scrape-uri: The URL of Nginx’sstub_statuspage.--web.listen-address: The port the exporter will listen on for Prometheus scrapes (default9113).--web.telemetry-path: The HTTP path that exposes metrics (default/metrics).
Reload systemd, enable the service, and start it:
sudo systemctl daemon-reload
sudo systemctl enable nginx-prometheus-exporter
sudo systemctl start nginx-prometheus-exporter
sudo systemctl status nginx-prometheus-exporter
Verify the exporter is serving metrics:
curl http://localhost:9113/metrics
You should see Prometheus text format output including metrics such as:
# HELP nginx_connections_accepted Accepted client connections
# TYPE nginx_connections_accepted counter
nginx_connections_accepted 1024
# HELP nginx_connections_active Active client connections
# TYPE nginx_connections_active gauge
nginx_connections_active 4
# HELP nginx_connections_handled Handled client connections
# TYPE nginx_connections_handled counter
nginx_connections_handled 1024
# HELP nginx_connections_reading Connections where Nginx is reading the request header
# TYPE nginx_connections_reading gauge
nginx_connections_reading 0
# HELP nginx_connections_waiting Idle client connections
# TYPE nginx_connections_waiting gauge
nginx_connections_waiting 3
# HELP nginx_connections_writing Connections where Nginx is writing the response
# TYPE nginx_connections_writing gauge
nginx_connections_writing 1
# HELP nginx_http_requests_total Total http requests
# TYPE nginx_http_requests_total counter
nginx_http_requests_total 8192
Step 5: Install Prometheus on RHEL 7
If you do not already have a Prometheus instance, install it on the same server or a dedicated monitoring server. Download the latest Prometheus release:
PROM_VERSION="2.52.0"
curl -L "https://github.com/prometheus/prometheus/releases/download/v${PROM_VERSION}/prometheus-${PROM_VERSION}.linux-amd64.tar.gz"
-o /tmp/prometheus.tar.gz
tar -xzf /tmp/prometheus.tar.gz -C /tmp
sudo mv /tmp/prometheus-${PROM_VERSION}.linux-amd64/{prometheus,promtool} /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo mv /tmp/prometheus-${PROM_VERSION}.linux-amd64/{consoles,console_libraries} /etc/prometheus/
Create a Prometheus system user:
sudo useradd --system --no-create-home --shell /sbin/nologin prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
Step 6: Configure Prometheus to Scrape the Nginx Exporter
Create the Prometheus configuration file at /etc/prometheus/prometheus.yml:
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'nginx'
static_configs:
- targets: ['localhost:9113']
scrape_interval: 10s
metrics_path: /metrics
Create the systemd service for Prometheus:
sudo tee /etc/systemd/system/prometheus.service <<'EOF'
[Unit]
Description=Prometheus
Documentation=https://prometheus.io/docs/
After=network.target
[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/usr/local/bin/prometheus
--config.file=/etc/prometheus/prometheus.yml
--storage.tsdb.path=/var/lib/prometheus/
--web.console.templates=/etc/prometheus/consoles
--web.console.libraries=/etc/prometheus/console_libraries
--web.listen-address=0.0.0.0:9090
--storage.tsdb.retention.time=30d
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
sudo systemctl status prometheus
Open the Prometheus port in the firewall if needed:
sudo firewall-cmd --permanent --add-port=9090/tcp
sudo firewall-cmd --reload
Access the Prometheus UI at http://your-server-ip:9090. Navigate to Status → Targets and confirm the nginx job shows UP state.
Step 7: Query Nginx Metrics in Prometheus
In the Prometheus expression browser, try these useful queries:
# Current active connections
nginx_connections_active
# Request rate over the last 5 minutes
rate(nginx_http_requests_total[5m])
# Connection acceptance rate
rate(nginx_connections_accepted[5m])
# Percentage of connections being handled vs accepted (should be 1.0)
rate(nginx_connections_handled[5m]) / rate(nginx_connections_accepted[5m])
Step 8: Import a Grafana Dashboard for Nginx
Install Grafana if needed:
sudo tee /etc/yum.repos.d/grafana.repo <<'EOF'
[grafana]
name=grafana
baseurl=https://packages.grafana.com/oss/rpm
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://packages.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF
sudo yum -y install grafana
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --reload
Access Grafana at http://your-server-ip:3000 (default credentials: admin / admin). Change the password immediately after login.
Add Prometheus as a data source:
- Navigate to Configuration → Data Sources → Add data source.
- Select Prometheus.
- Set the URL to
http://localhost:9090. - Click Save & Test.
Import the official Nginx dashboard. The most popular is Dashboard ID 12708 (NGINX exporter) from Grafana Labs:
- Navigate to Dashboards → Import.
- Enter dashboard ID
12708and click Load. - Select your Prometheus data source.
- Click Import.
The imported dashboard provides panels for active connections, requests per second, connection states (reading, writing, waiting), and historical trends. You can also use Dashboard ID 9614 for an alternative layout.
Conclusion
You now have a complete Nginx monitoring pipeline on RHEL 7: Nginx’s stub_status module exposes raw connection and request data at /nginx_status, the nginx-prometheus-exporter service reads that data and translates it into Prometheus text format at port 9113, Prometheus scrapes it every 10–15 seconds and stores it in its time-series database, and Grafana visualizes historical trends and real-time metrics on an importable dashboard. While stub_status provides only basic counters, this setup is lightweight and sufficient for capacity planning and alerting on connection spikes or request rate anomalies. For deeper application-layer visibility such as per-upstream response times and HTTP status code breakdowns, consider the Nginx Plus API or a log-based exporter like grok_exporter or mtail.