VPS Monitoring with Prometheus and Grafana: Setting Up Metrics Collection and Alerting on a Single Server

Monitoring a VPS is not optional once you have more than one server or a production application. Prometheus collects metrics from your servers and applications. Grafana visualizes them in dashboards. Together, they give you a real-time view of CPU, memory, disk, network, and application-level metrics with configurable alerting. This guide covers installing both on a single VPS, configuring exporters, building dashboards, and setting up alerts that catch problems before users do.

Why Prometheus + Grafana on a VPS

Managed monitoring services (Datadog, New Relic) start at $15–$30 per host per month. Prometheus and Grafana are open source and free. On a 2 GB VPS, the full stack (Prometheus, Grafana, Node Exporter, and Alertmanager) consumes approximately 300–500 MB of RAM and handles up to 50 monitored targets without performance degradation.

ComponentMemory UsageCPU (Idle)Disk (30 days retention)
Prometheus150–250 MB2–5%2–5 GB
Grafana80–120 MB1–2%100 MB
Node Exporter10–20 MB<1%Minimal
Alertmanager20–30 MB<1%Minimal
Total260–420 MB3–8%2–5 GB

Step 1: Install Prometheus

# Download and install Prometheus
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.52.0/prometheus-2.52.0.linux-amd64.tar.gz
tar xzf prometheus-2.52.0.linux-amd64.tar.gz
sudo mv prometheus-2.52.0.linux-amd64 /opt/prometheus

# Create a system user
sudo useradd --no-create-home --shell /bin/false prometheus

# Set ownership
sudo chown -R prometheus:prometheus /opt/prometheus

Create a minimal configuration at /opt/prometheus/prometheus.yml:

# /opt/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets: ['localhost:9093']

# Rule files for alerting
rule_files:
  - "rules/*.yml"

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

  - job_name: 'node'
    static_configs:
      - targets: ['localhost:9100']

Create a systemd service at /etc/systemd/system/prometheus.service:

[Unit]
Description=Prometheus
After=network.target

[Service]
User=prometheus
Group=prometheus
Type=simple
ExecStart=/opt/prometheus/prometheus \
    --config.file=/opt/prometheus/prometheus.yml \
    --storage.tsdb.path=/opt/prometheus/data \
    --storage.tsdb.retention.time=30d \
    --web.console.templates=/opt/prometheus/consoles \
    --web.console.libraries=/opt/prometheus/console_libraries

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

Step 2: Install Node Exporter (System Metrics)

Node Exporter exposes CPU, memory, disk, and network metrics from the Linux kernel:

cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
tar xzf node_exporter-1.8.1.linux-amd64.tar.gz
sudo cp node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/

sudo useradd --no-create-home --shell /bin/false node_exporter
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter

Create systemd service at /etc/systemd/system/node_exporter.service:

[Unit]
Description=Node Exporter
After=network.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter \
    --collector.cpu \
    --collector.diskstats \
    --collector.filesystem \
    --collector.meminfo \
    --collector.netdev \
    --collector.loadavg

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

Step 3: Install Grafana

# Add Grafana repository (Ubuntu/Debian)
sudo apt install -y software-properties-common
sudo add-apt-repository "deb https://packages.grafana.com/oss/deb stable main"
wget -q -O - https://packages.grafana.com/gpg.key | sudo apt-key add -
sudo apt update
sudo apt install grafana -y

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

Grafana runs on port 3000. Default credentials are admin/admin. Change the password immediately after login.

Step 4: Add Prometheus as a Data Source in Grafana

In the Grafana UI (http://your-vps:3000):

  1. Navigate to Configuration → Data Sources → Add data source.
  2. Select Prometheus.
  3. Set URL to http://localhost:9090.
  4. Click Save & Test.

Step 5: Import a Pre-Built Dashboard

Grafana has a community dashboard library. Import the popular Node Exporter Full dashboard (ID 1860):

  1. Navigate to Dashboards → Import.
  2. Enter 1860 in the Grafana.com dashboard ID field.
  3. Select your Prometheus data source.
  4. Click Import.

You will see CPU usage, memory, disk I/O, network traffic, and system load in real time.

Step 6: Configure Alerting

Create alert rules in /opt/prometheus/rules/vps.yml:

# /opt/prometheus/rules/vps.yml
groups:
  - name: vps_alerts
    rules:
      # Disk space alert
      - alert: DiskSpaceLow
        expr: (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100  90
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Memory usage above 90% on {{ $labels.instance }}"
          description: "Memory usage is {{ $value }}%."

      # CPU alert
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "CPU usage above 80% for 10 minutes on {{ $labels.instance }}"
          description: "CPU usage is {{ $value }}%."

      # System load alert
      - alert: HighSystemLoad
        expr: node_load15 / count without(cpu, mode) (node_cpu_seconds_total{mode="idle"}) > 1.5
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "System load too high on {{ $labels.instance }}"
          description: "15-minute load average is {{ $value }} times the number of CPUs."

      # Target down alert
      - alert: TargetDown
        expr: up == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Target {{ $labels.instance }} is down"
          description: "{{ $labels.job }} on {{ $labels.instance }} has been unreachable for 2 minutes."

Reload Prometheus to pick up the new rules:

sudo systemctl reload prometheus

Step 7: Set Up Alert Notifications

Configure Alertmanager for email notifications at /opt/prometheus/alertmanager.yml:

# /opt/prometheus/alertmanager.yml
global:
  smtp_smarthost: 'smtp.gmail.com:587'
  smtp_from: '[email protected]'
  smtp_auth_username: '[email protected]'
  smtp_auth_password: 'your-app-password'

route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'email'

receivers:
  - name: 'email'
    email_configs:
      - to: '[email protected]'

Securing the Stack

  • Reverse proxy with TLS: Put Grafana behind Nginx with SSL. Grafana on port 3000 over HTTP is fine on localhost, but expose it with HTTPS.
  • Authentication: Grafana has built-in auth. Prometheus has no built-in auth — use Nginx basic auth or OAuth2 proxy in front of it.
  • Firewall: Only expose ports 80/443 (Nginx) and 22 (SSH). Prometheus (9090), Grafana (3000), and Node Exporter (9100) should be accessible only from localhost or via the reverse proxy.
  • Data retention: The --storage.tsdb.retention.time=30d flag limits Prometheus data storage to 30 days. Adjust based on your disk size. On a 20 GB VPS, 30 days is safe for up to 10 monitored targets.

For a VPS with adequate resources to run this monitoring stack alongside your applications, compare VPS plans with suitable RAM and storage. For more on performance optimization and server management, explore our performance tuning guides.

Leave a Reply