Set up NGINX monitoring with Prometheus and Grafana for web server observability

Intermediate 45 min Apr 17, 2026 193 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Monitor your NGINX web server performance and health with Prometheus metrics collection and Grafana dashboards. Set up comprehensive observability including request rates, response times, error tracking, and automated alerting for production web servers.

Prerequisites

  • NGINX web server running
  • Root or sudo access
  • At least 2GB RAM available
  • Ports 3000, 9090, 9093 available

What this solves

NGINX monitoring gives you visibility into web server performance, request patterns, and error rates before problems affect users. This tutorial sets up Prometheus to collect NGINX metrics via the nginx-prometheus-exporter, configures Grafana dashboards for visualization, and implements alerting rules for proactive incident response.

Step-by-step installation

Update system packages

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

sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl gnupg2
sudo dnf update -y
sudo dnf install -y wget curl gnupg2

Install Prometheus

Download and install Prometheus server to collect and store NGINX metrics data.

cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.48.0/prometheus-2.48.0.linux-amd64.tar.gz
tar xzf prometheus-2.48.0.linux-amd64.tar.gz
sudo mv prometheus-2.48.0.linux-amd64 /opt/prometheus
sudo useradd --no-create-home --shell /bin/false prometheus
sudo mkdir -p /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /opt/prometheus/prometheus /opt/prometheus/promtool

Configure Prometheus systemd service

Create a systemd service file to manage Prometheus as a system service with proper permissions and startup configuration.

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

[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/opt/prometheus/prometheus \
    --config.file /etc/prometheus/prometheus.yml \
    --storage.tsdb.path /var/lib/prometheus/ \
    --web.console.templates=/opt/prometheus/consoles \
    --web.console.libraries=/opt/prometheus/console_libraries \
    --web.listen-address=0.0.0.0:9090 \
    --web.enable-lifecycle

[Install]
WantedBy=multi-user.target

Configure NGINX stub status module

Enable NGINX's stub_status module to expose basic metrics that Prometheus can scrape.

server {
    listen 8080;
    server_name localhost;
    
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 127.0.0.1;
        allow ::1;
        deny all;
    }
}

Test the NGINX configuration and reload the service.

sudo nginx -t
sudo systemctl reload nginx

Install NGINX Prometheus Exporter

Download and configure the nginx-prometheus-exporter to convert NGINX metrics into Prometheus format.

cd /tmp
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v0.11.0/nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
tar xzf nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz
sudo mv nginx-prometheus-exporter /usr/local/bin/
sudo useradd --no-create-home --shell /bin/false nginx-exporter

Configure NGINX Exporter service

Create a systemd service for the NGINX exporter to run continuously and expose metrics on port 9113.

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

[Service]
User=nginx-exporter
Group=nginx-exporter
Type=simple
ExecStart=/usr/local/bin/nginx-prometheus-exporter \
    -nginx.scrape-uri=http://localhost:8080/nginx_status \
    -web.listen-address=:9113
Restart=on-failure

[Install]
WantedBy=multi-user.target

Configure Prometheus to scrape NGINX metrics

Set up Prometheus configuration to collect metrics from the NGINX exporter and define scrape intervals.

global:
  scrape_interval: 15s
  evaluation_interval: 15s

rule_files:
  - "nginx_alerts.yml"

alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - localhost:9093

scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']

  - job_name: 'nginx'
    static_configs:
      - targets: ['localhost:9113']
    scrape_interval: 10s
    metrics_path: /metrics

Set proper ownership for the configuration file.

sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml

Install Grafana

Add the Grafana repository and install Grafana for creating monitoring dashboards.

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 <

Configure NGINX alerting rules

Create alerting rules for common NGINX issues like high error rates, connection problems, and performance degradation.

groups:
  • name: nginx_alerts
rules: - alert: NginxHighErrorRate expr: rate(nginx_http_requests_total{status=~"5.."}[5m]) > 0.1 for: 5m labels: severity: warning annotations: summary: "NGINX high error rate detected" description: "NGINX error rate is {{ $value }} errors per second" - alert: NginxHighRequestRate expr: rate(nginx_http_requests_total[5m]) > 100 for: 2m labels: severity: warning annotations: summary: "NGINX high request rate" description: "NGINX is receiving {{ $value }} requests per second" - alert: NginxDown expr: up{job="nginx"} == 0 for: 1m labels: severity: critical annotations: summary: "NGINX exporter is down" description: "NGINX exporter has been down for more than 1 minute" - alert: NginxHighConnectionsActive expr: nginx_connections_active > 1000 for: 5m labels: severity: warning annotations: summary: "NGINX high active connections" description: "NGINX has {{ $value }} active connections"

Set proper ownership for the alerts file.

sudo chown prometheus:prometheus /etc/prometheus/nginx_alerts.yml

Start and enable all services

Enable and start Prometheus, NGINX exporter, and Grafana services to begin monitoring.

sudo systemctl daemon-reload
sudo systemctl enable --now prometheus
sudo systemctl enable --now nginx-exporter
sudo systemctl enable --now grafana-server

Configure Grafana data source

Access Grafana web interface and add Prometheus as a data source for NGINX metrics visualization.

curl -X POST http://admin:admin@localhost:3000/api/datasources \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Prometheus",
    "type": "prometheus",
    "url": "http://localhost:9090",
    "access": "proxy",
    "basicAuth": false,
    "isDefault": true
  }'
Note: Default Grafana credentials are admin/admin. Change these on first login for security.

Import NGINX dashboard

Create a comprehensive Grafana dashboard showing NGINX request rates, response times, status codes, and connection metrics.

{
  "dashboard": {
    "title": "NGINX Monitoring",
    "tags": ["nginx", "prometheus"],
    "timezone": "browser",
    "panels": [
      {
        "title": "Requests per Second",
        "type": "graph",
        "targets": [{
          "expr": "rate(nginx_http_requests_total[5m])",
          "legendFormat": "Requests/sec"
        }]
      },
      {
        "title": "HTTP Status Codes",
        "type": "graph",
        "targets": [{
          "expr": "rate(nginx_http_requests_total[5m])",
          "legendFormat": "{{status}}"
        }]
      },
      {
        "title": "Active Connections",
        "type": "singlestat",
        "targets": [{
          "expr": "nginx_connections_active"
        }]
      },
      {
        "title": "Connection States",
        "type": "graph",
        "targets": [
          {"expr": "nginx_connections_accepted", "legendFormat": "Accepted"},
          {"expr": "nginx_connections_handled", "legendFormat": "Handled"},
          {"expr": "nginx_connections_reading", "legendFormat": "Reading"},
          {"expr": "nginx_connections_writing", "legendFormat": "Writing"},
          {"expr": "nginx_connections_waiting", "legendFormat": "Waiting"}
        ]
      }
    ],
    "time": {"from": "now-1h", "to": "now"},
    "refresh": "10s"
  }
}

Import the dashboard via Grafana API.

curl -X POST http://admin:admin@localhost:3000/api/dashboards/db \
  -H "Content-Type: application/json" \
  -d @/tmp/nginx-dashboard.json

Configure firewall rules

Open the necessary ports for Prometheus, Grafana, and NGINX monitoring while maintaining security.

sudo ufw allow 3000/tcp comment 'Grafana'
sudo ufw allow 9090/tcp comment 'Prometheus'
sudo ufw allow from 127.0.0.1 to any port 9113 comment 'NGINX Exporter'
sudo ufw allow from 127.0.0.1 to any port 8080 comment 'NGINX Status'
sudo firewall-cmd --permanent --add-port=3000/tcp --add-port=9090/tcp
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="127.0.0.1" port protocol="tcp" port="9113" accept'
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="127.0.0.1" port protocol="tcp" port="8080" accept'
sudo firewall-cmd --reload

Verify your setup

Check that all services are running properly and metrics are being collected.

sudo systemctl status prometheus nginx-exporter grafana-server
curl http://localhost:9090/api/v1/targets
curl http://localhost:9113/metrics | grep nginx
curl http://localhost:8080/nginx_status

Access the web interfaces to confirm everything is working:

  • Prometheus: http://your-server:9090
  • Grafana: http://your-server:3000 (admin/admin)

Set up Prometheus Alertmanager

Configure Alertmanager to handle alert notifications from Prometheus rules. This tutorial pairs well with our comprehensive Prometheus Alertmanager guide for email notifications.

Install Alertmanager

Download and install Alertmanager to handle alert routing and notifications.

cd /tmp
wget https://github.com/prometheus/alertmanager/releases/download/v0.26.0/alertmanager-0.26.0.linux-amd64.tar.gz
tar xzf alertmanager-0.26.0.linux-amd64.tar.gz
sudo mv alertmanager-0.26.0.linux-amd64/alertmanager /usr/local/bin/
sudo mv alertmanager-0.26.0.linux-amd64/amtool /usr/local/bin/
sudo useradd --no-create-home --shell /bin/false alertmanager
sudo mkdir -p /etc/alertmanager /var/lib/alertmanager
sudo chown alertmanager:alertmanager /etc/alertmanager /var/lib/alertmanager

Configure basic Alertmanager

Set up a basic Alertmanager configuration for webhook notifications or email alerts.

global:
  smtp_smarthost: 'localhost:587'
  smtp_from: 'alertmanager@example.com'

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'web.hook'

receivers:
  • name: 'web.hook'
webhook_configs: - url: 'http://localhost:5001/' email_configs: - to: 'admin@example.com' subject: 'NGINX Alert: {{ .GroupLabels.alertname }}' body: | {{ range .Alerts }} Alert: {{ .Annotations.summary }} Description: {{ .Annotations.description }} {{ end }}

Set proper ownership and create the systemd service.

sudo chown alertmanager:alertmanager /etc/alertmanager/alertmanager.yml

Create Alertmanager service

Configure Alertmanager as a systemd service for automatic startup and management.

[Unit]
Description=Alertmanager
Wants=network-online.target
After=network-online.target

[Service]
User=alertmanager
Group=alertmanager
Type=simple
ExecStart=/usr/local/bin/alertmanager \
    --config.file /etc/alertmanager/alertmanager.yml \
    --storage.path /var/lib/alertmanager/ \
    --web.external-url http://localhost:9093

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now alertmanager

Advanced dashboard configuration

Enhance your NGINX monitoring with additional metrics and visualizations for better observability.

Add log-based metrics

Configure NGINX log parsing to extract additional performance metrics like response times and request patterns.

log_format prometheus '$remote_addr - $remote_user [$time_local] '
                     '"$request" $status $body_bytes_sent '
                     '"$http_referer" "$http_user_agent" '
                     'rt=$request_time uct="$upstream_connect_time" '
                     'uht="$upstream_header_time" urt="$upstream_response_time"';

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

Performance tuning

Optimize your monitoring setup for production environments and high-traffic websites.

ComponentTuning ParameterRecommended Value
Prometheusscrape_interval15s for production, 5s for development
NGINX ExporterRate limitingEnable if handling >1000 RPS
GrafanaRefresh rate30s minimum for production dashboards
StorageRetention period15 days for metrics, 7 days for logs

Common issues

SymptomCauseFix
NGINX exporter shows no datastub_status not accessibleCheck /nginx_status endpoint and firewall rules
Prometheus can't scrape targetsService discovery issuesVerify target endpoints with curl localhost:9113/metrics
Grafana shows no dataData source misconfigurationTest Prometheus connection in Grafana settings
High memory usageToo many metrics collectedIncrease scrape_interval or filter metrics
Alerts not firingAlertmanager not connectedCheck Prometheus alert rules with /alerts endpoint
Dashboard panels emptyWrong query syntaxTest queries in Prometheus Graph tab first

Security considerations

Secure your monitoring infrastructure with proper authentication and network restrictions.

Security Warning: The NGINX status endpoint exposes server information. Restrict access to monitoring networks only and never expose it publicly.
  • Enable Grafana authentication and change default passwords
  • Use HTTPS for Grafana in production environments
  • Restrict Prometheus and exporter access to monitoring networks
  • Regularly update all components for security patches
  • Consider using Prometheus authentication if exposing externally

For production deployments, consider integrating with our PostgreSQL monitoring setup for comprehensive database and web server observability.

Next steps

Running this in production?

Want this handled for you? 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.