Configure NGINX monitoring with Prometheus and Grafana dashboards for real-time web server performance metrics

Intermediate 45 min Apr 23, 2026 27 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Set up comprehensive NGINX monitoring using Prometheus metrics collection and custom Grafana dashboards to track web server performance, request rates, and response times in real-time.

Prerequisites

  • Root or sudo access
  • Basic knowledge of NGINX configuration
  • Familiarity with systemd services

What this solves

NGINX monitoring with Prometheus and Grafana provides real-time visibility into your web server's performance metrics. This setup tracks request rates, response times, active connections, and server health status through automated metrics collection and customizable dashboards.

Step-by-step configuration

Update system packages

Start by updating your package manager to ensure you get the latest versions.

sudo apt update && sudo apt upgrade -y
sudo dnf update -y

Install NGINX with stub_status module

Install NGINX and verify the stub_status module is available for metrics collection.

sudo apt install -y nginx
sudo nginx -V 2>&1 | grep -o with-http_stub_status_module
sudo dnf install -y nginx
sudo nginx -V 2>&1 | grep -o with-http_stub_status_module

Configure NGINX stub_status endpoint

Enable the stub_status module to expose basic NGINX metrics at a dedicated endpoint.

server {
    listen 80;
    server_name example.com;
    
    location / {
        root /var/www/html;
        index index.html index.htm;
    }
    
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        allow ::1;
        deny all;
    }
}

Test NGINX configuration

Validate the configuration syntax and reload NGINX to apply changes.

sudo nginx -t
sudo systemctl reload nginx
sudo systemctl enable nginx

Verify stub_status endpoint

Test that the stub_status endpoint is working and returning metrics.

curl http://localhost/nginx_status

You should see output like:

Active connections: 1 
server accepts handled requests
 1 1 1 
Reading: 0 Writing: 1 Waiting: 0

Install Prometheus NGINX Exporter

Download and install the official NGINX Prometheus exporter to convert stub_status metrics to Prometheus format.

wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v1.1.0/nginx-prometheus-exporter_1.1.0_linux_amd64.tar.gz
tar -xzf nginx-prometheus-exporter_1.1.0_linux_amd64.tar.gz
sudo mv nginx-prometheus-exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/nginx-prometheus-exporter

Create systemd service for NGINX exporter

Set up the NGINX exporter as a systemd service for automatic startup and management.

[Unit]
Description=NGINX Prometheus Exporter
After=network.target

[Service]
Type=simple
User=nginx
Group=nginx
ExecStart=/usr/local/bin/nginx-prometheus-exporter -nginx.scrape-uri=http://localhost/nginx_status
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Create nginx user for exporter

Create a dedicated system user for running the NGINX exporter service.

sudo useradd --system --no-create-home --shell /bin/false nginx-exporter
sudo sed -i 's/User=nginx/User=nginx-exporter/' /etc/systemd/system/nginx-prometheus-exporter.service
sudo sed -i 's/Group=nginx/Group=nginx-exporter/' /etc/systemd/system/nginx-prometheus-exporter.service
sudo useradd --system --no-create-home --shell /bin/false nginx-exporter
sudo sed -i 's/User=nginx/User=nginx-exporter/' /etc/systemd/system/nginx-prometheus-exporter.service
sudo sed -i 's/Group=nginx/Group=nginx-exporter/' /etc/systemd/system/nginx-prometheus-exporter.service

Start NGINX exporter service

Enable and start the NGINX Prometheus exporter service.

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

Install Prometheus server

Install Prometheus to collect and store metrics from the NGINX exporter.

wget https://github.com/prometheus/prometheus/releases/download/v2.45.0/prometheus-2.45.0.linux-amd64.tar.gz
tar -xzf prometheus-2.45.0.linux-amd64.tar.gz
sudo mv prometheus-2.45.0.linux-amd64/prometheus /usr/local/bin/
sudo mv prometheus-2.45.0.linux-amd64/promtool /usr/local/bin/
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo useradd --system --no-create-home --shell /bin/false prometheus

Configure Prometheus to scrape NGINX metrics

Create the main Prometheus configuration file to scrape metrics from the NGINX exporter.

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: 5s
    metrics_path: /metrics

Set Prometheus permissions

Configure correct ownership and permissions for Prometheus directories and files.

sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chmod -R 755 /etc/prometheus /var/lib/prometheus

Create Prometheus systemd service

Set up Prometheus as a systemd service for automatic startup and management.

[Unit]
Description=Prometheus
After=network-online.target

[Service]
Type=simple
User=prometheus
Group=prometheus
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 \
  --web.enable-lifecycle
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Start Prometheus service

Enable and start the Prometheus service.

sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl status prometheus

Install Grafana

Install Grafana for creating dashboards and visualizing NGINX metrics.

wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://packages.grafana.com/oss/deb stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install -y grafana
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
EOF
sudo dnf install -y grafana

Start Grafana service

Enable and start the Grafana service.

sudo systemctl daemon-reload
sudo systemctl enable --now grafana-server
sudo systemctl status grafana-server

Configure firewall rules

Open necessary ports for Prometheus and Grafana web interfaces.

sudo ufw allow 3000/tcp comment 'Grafana'
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow 9113/tcp comment 'NGINX Exporter'
sudo ufw reload
sudo firewall-cmd --permanent --add-port=3000/tcp
sudo firewall-cmd --permanent --add-port=9090/tcp
sudo firewall-cmd --permanent --add-port=9113/tcp
sudo firewall-cmd --reload

Add Prometheus data source in Grafana

Access Grafana at http://your-server-ip:3000 with default credentials admin/admin. Add Prometheus as a data source with URL http://localhost:9090.

Name: Prometheus
Type: Prometheus
URL: http://localhost:9090
Access: Server (default)
Scrape interval: 15s

Import NGINX dashboard

Create a comprehensive NGINX monitoring dashboard with key metrics and visualizations.

{
  "dashboard": {
    "title": "NGINX Monitoring",
    "panels": [
      {
        "title": "Active Connections",
        "type": "stat",
        "targets": [{
          "expr": "nginx_connections_active"
        }]
      },
      {
        "title": "Request Rate",
        "type": "graph",
        "targets": [{
          "expr": "rate(nginx_connections_handled[5m])"
        }]
      },
      {
        "title": "Connection States",
        "type": "graph",
        "targets": [
          {
            "expr": "nginx_connections_reading",
            "legendFormat": "Reading"
          },
          {
            "expr": "nginx_connections_writing",
            "legendFormat": "Writing"
          },
          {
            "expr": "nginx_connections_waiting",
            "legendFormat": "Waiting"
          }
        ]
      }
    ]
  }
}

Verify your setup

Test that all components are working correctly and collecting metrics.

# Check NGINX exporter metrics
curl http://localhost:9113/metrics | grep nginx_

Check Prometheus targets

curl http://localhost:9090/api/v1/targets | grep nginx

Check service status

sudo systemctl status nginx nginx-prometheus-exporter prometheus grafana-server

Generate test traffic

for i in {1..10}; do curl http://localhost/; sleep 1; done
Important metrics to monitor: Key NGINX metrics include nginx_connections_active, nginx_connections_handled, nginx_connections_reading, nginx_connections_writing, and nginx_connections_waiting.

Set up alerting rules

Configure Prometheus alerting rules for critical NGINX conditions and integrate with your existing monitoring setup such as Prometheus Alertmanager.

groups:
  • name: nginx_alerts
rules: - alert: NginxDown expr: up{job="nginx"} == 0 for: 5m labels: severity: critical annotations: summary: "NGINX exporter is down" description: "NGINX exporter has been down for more than 5 minutes." - alert: NginxHighConnections expr: nginx_connections_active > 1000 for: 10m labels: severity: warning annotations: summary: "High number of active NGINX connections" description: "NGINX has {{ $value }} active connections for more than 10 minutes." - alert: NginxHighRequestRate expr: rate(nginx_connections_handled[5m]) > 100 for: 5m labels: severity: warning annotations: summary: "High NGINX request rate" description: "NGINX request rate is {{ $value }} requests per second."

Advanced dashboard configuration

Enhance your NGINX monitoring with additional panels and metrics for comprehensive observability similar to production monitoring stacks.

Add request duration metrics

Configure NGINX to log request processing times for latency monitoring.

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for" '
                    'rt=$request_time uct="$upstream_connect_time" '
                    'uht="$upstream_header_time" urt="$upstream_response_time"';
    
    access_log /var/log/nginx/access.log main;
    
    server {
        location /metrics {
            access_log off;
            return 200 "# NGINX metrics exported to Prometheus\n";
            add_header Content-Type text/plain;
        }
    }
}

Common issues

SymptomCauseFix
NGINX exporter not startingPermission denied on stub_statusCheck allow 127.0.0.1 in NGINX config
No metrics in PrometheusIncorrect scrape configurationVerify targets: ['localhost:9113'] in prometheus.yml
Grafana shows no dataData source not configuredAdd Prometheus data source with URL http://localhost:9090
Connection refused on port 9113NGINX exporter service downsudo systemctl restart nginx-prometheus-exporter
Permission denied errorsIncorrect file ownershipsudo chown prometheus:prometheus /etc/prometheus -R
Security note: The stub_status endpoint exposes server metrics. Restrict access using allow and deny directives to prevent unauthorized access.

Next steps

Running this in production?

Need enterprise monitoring? Setting up NGINX monitoring once is straightforward. Keeping it patched, monitored, backed up and tuned across environments is the harder part. See how we run infrastructure like this for European SaaS and e-commerce teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle managed devops services for businesses that depend on uptime. From initial setup to ongoing operations.