
Table of Contents
Why Monitor Your VPS
When your website or application slows down or crashes, the first question is: "What happened?" Without monitoring, you're flying blind — forced to SSH in and run top or df -h manually, with no historical context to understand what led up to the problem.
Prometheus + Grafana is the most widely adopted self-hosted monitoring stack in production environments. It installs on any VPS for free and gives you deeper visibility than expensive SaaS monitoring tools.
| Metric | Tool | Why It Matters |
|---|---|---|
| CPU usage | Node Exporter → Prometheus | Catch spikes before users notice |
| RAM free/used | Node Exporter → Prometheus | Plan upgrades based on real data |
| Disk I/O & usage | Node Exporter → Prometheus | Prevent disk-full that corrupts databases |
| Network traffic | Node Exporter → Prometheus | Detect unusual traffic or early DDoS |
| Custom app metrics | Client library → Prometheus | Track request rate and error rates |
Prometheus + Grafana Architecture
Before installing, understand the components:
- Node Exporter — runs on the monitored VPS, exposes OS metrics via HTTP on port 9100
- Prometheus — scrapes metrics from Node Exporter every 15 seconds and stores them in its time-series database
- Grafana — connects to Prometheus as a data source and renders metrics as interactive dashboards
- Alertmanager (optional) — receives alerts from Prometheus and routes them to Email, Slack, or webhooks
Installing Prometheus
Download and install Prometheus on Ubuntu 22.04:
# Create a dedicated system user
sudo useradd --no-create-home --shell /bin/false prometheus
# Create directories
sudo mkdir /etc/prometheus /var/lib/prometheus
# Download Prometheus (check latest version at github.com/prometheus/prometheus)
PROM_VER="2.53.0"
wget https://github.com/prometheus/prometheus/releases/download/v${PROM_VER}/prometheus-${PROM_VER}.linux-amd64.tar.gz
tar -xzf prometheus-${PROM_VER}.linux-amd64.tar.gz
cd prometheus-${PROM_VER}.linux-amd64/
# Copy binaries
sudo cp prometheus /usr/local/bin/
sudo cp promtool /usr/local/bin/
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
# Copy config files
sudo cp -r consoles/ /etc/prometheus/
sudo cp -r console_libraries/ /etc/prometheus/
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
Create the initial config file
sudo nano /etc/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
Create a systemd service
sudo nano /etc/systemd/system/prometheus.service
[Unit]
Description=Prometheus
Wants=network-online.target
After=network-online.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 \
--storage.tsdb.retention.time=30d
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable prometheus
sudo systemctl start prometheus
sudo systemctl status prometheus
Installing Node Exporter
Node Exporter collects OS-level metrics — CPU, RAM, Disk, Network:
NODE_VER="1.8.1"
wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_VER}/node_exporter-${NODE_VER}.linux-amd64.tar.gz
tar -xzf node_exporter-${NODE_VER}.linux-amd64.tar.gz
sudo cp node_exporter-${NODE_VER}.linux-amd64/node_exporter /usr/local/bin/
sudo useradd --no-create-home --shell /bin/false node_exporter
sudo nano /etc/systemd/system/node_exporter.service
[Unit]
Description=Node Exporter
Wants=network-online.target
After=network-online.target
[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter
Verify Node Exporter is running: curl http://localhost:9100/metrics | head -20
Configuring Prometheus Scrape Jobs
The prometheus.yml config above already targets localhost:9100. Verify Node Exporter is being scraped by visiting the Prometheus UI:
http://YOUR_VPS_IP:9090 → Status → Targets → the node endpoint should show UP
Try these example queries in the Prometheus UI Expression box:
# CPU usage (%)
100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# RAM used (bytes)
node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes
# Disk usage (%)
(node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes * 100
Installing Grafana
Grafana can be installed from the official apt repository:
sudo apt-get install -y apt-transport-https software-properties-common wget
wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/grafana.gpg > /dev/null
echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y grafana
sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
Open http://YOUR_VPS_IP:3000 in your browser → log in with admin / admin → you'll be prompted to change the password immediately.
Creating Your First Dashboard
Connect Prometheus as a Grafana data source:
- In Grafana UI → Connections → Data sources → Add data source → select Prometheus
- URL:
http://localhost:9090→ Save & test → should show "Data source is working" - Import a ready-made dashboard → Dashboards → Import → enter ID 1860 → Load → select your Prometheus data source → Import
| Panel in Dashboard 1860 | Data Shown |
|---|---|
| CPU Basic | User, System, IOWait, Idle % |
| Memory Basic | Total, Used, Free, Buffers/Cache |
| Disk Space Used % | Usage % per partition |
| Network Traffic | Received/Transmitted bytes/s |
| System Load | 1m, 5m, 15m load average |
| Disk I/O | Read/Write bytes/s |
Setting Up CPU/RAM Alerts
Add alert rules to Prometheus to trigger notifications when thresholds are exceeded:
sudo nano /etc/prometheus/alert.rules.yml
groups:
- name: node_alerts
rules:
- alert: HighCPU
expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 5m
labels:
severity: warning
annotations:
summary: "High CPU {{ $value }}%"
description: "Instance {{ $labels.instance }} CPU usage above 85% for 5 minutes"
- alert: LowMemory
expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 15
for: 5m
labels:
severity: critical
annotations:
summary: "Low RAM {{ $value }}% available"
description: "Instance {{ $labels.instance }} has less than 15% available RAM"
- alert: DiskAlmostFull
expr: (node_filesystem_size_bytes - node_filesystem_free_bytes) / node_filesystem_size_bytes * 100 > 85
for: 10m
labels:
severity: warning
annotations:
summary: "Disk {{ $value }}% used"
description: "Disk on {{ $labels.instance }} ({{ $labels.mountpoint }}) is {{ $value }}% full"
Add the rule file to prometheus.yml:
rule_files:
- "/etc/prometheus/alert.rules.yml"
sudo systemctl reload prometheus
Security — Firewall and Basic Auth
By default, Prometheus (9090) and Node Exporter (9100) are accessible from any IP. Lock them down:
# Block external access to Prometheus and Node Exporter
sudo ufw deny 9090
sudo ufw deny 9100
# Or allow only your own IP
sudo ufw allow from YOUR_OFFICE_IP to any port 9090
ssh -L 9090:localhost:9090 user@YOUR_VPS_IP then open http://localhost:9090 on your local machine. Much safer than exposing the port publicly.
Grafana authentication settings
sudo nano /etc/grafana/grafana.ini
[auth.anonymous]
enabled = false
[security]
admin_password = YOUR_STRONG_PASSWORD
Summary
You now have a complete self-hosted monitoring stack. Here's what was set up:
- Prometheus installed as the time-series metrics database, scraping every 15 seconds
- Node Exporter exposing OS metrics (CPU, RAM, Disk, Network) on port 9100
- Grafana connected to Prometheus with Dashboard 1860 ready to use
- Alert rules for CPU >85%, RAM <15% free, and Disk >85% full
- Firewall rules blocking direct external access to Prometheus and Node Exporter
With this setup, you have the historical data to make informed scaling decisions — no more guessing when to upgrade. If you need a VPS with enough resources to run Prometheus + Grafana alongside your application, see AsiaGB VPS packages.
FAQ
What is the difference between Prometheus and Grafana?
Prometheus is a time-series database that collects and stores metrics. Grafana is a visualization platform that reads from Prometheus and renders the data as interactive dashboards. They complement each other perfectly.
What is Node Exporter?
Node Exporter is a lightweight agent that runs on Linux and exposes OS-level metrics via an HTTP endpoint on port 9100. Prometheus scrapes this endpoint periodically to collect CPU, RAM, Disk, and Network data.
How much RAM does this stack need?
Prometheus + Grafana + Node Exporter combined use approximately 400-600 MB of RAM. A VPS with at least 2 GB RAM is recommended for comfortable operation alongside your main workload.
Can I send alerts to Slack or LINE Notify?
Yes — Alertmanager supports Slack natively. For LINE Notify, use a webhook receiver in Alertmanager or configure a notification channel in Grafana Alerting, which has direct LINE Notify support.
Is Dashboard ID 1860 usable right away?
Yes — just import it by ID from Grafana's dashboard library, select Prometheus as the data source, and you get a fully functional CPU, RAM, Disk, and Network dashboard with no manual query configuration.
How long does Prometheus retain data?
The default retention period is 15 days. Extend it with --storage.tsdb.retention.time=30d. Typical disk usage for 30-day retention is 2-5 GB depending on the number of tracked metrics.