Monitor VPS with Grafana + Prometheus Pro
Professional VPS monitoring is no longer difficult. With the powerful duo of Prometheus and Grafana, you can view CPU, RAM, Disk, and Network in real-time with beautiful dashboards and automatic alerts when metrics exceed your defined thresholds. This article will guide you through a complete setup from zero to production on an Ubuntu/Debian VPS.
System Architecture
Before we start, understand each component:
- Node Exporter — a small agent that runs on your VPS to expose system metrics endpoints (CPU/RAM/Disk/Network)
- Prometheus — a time-series database that scrapes (pulls) metrics from Node Exporter every 15 seconds
- Grafana — a dashboard engine that reads data from Prometheus and displays it as beautiful graphs, with alerting capabilities
Step 1: Prepare VPS and Update System
Start by updating packages and creating dedicated users to run services for security.
sudo apt update && sudo apt upgrade -y
sudo useradd --no-create-home --shell /bin/false prometheus
sudo useradd --no-create-home --shell /bin/false node_exporter
Step 2: Install Node Exporter
Node Exporter is an agent that opens an HTTP endpoint on port 9100 for Prometheus to pull machine metrics from.
# Download latest Node Exporter version
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v1.8.1/node_exporter-1.8.1.linux-amd64.tar.gz
tar xvf node_exporter-1.8.1.linux-amd64.tar.gz
# Copy binary to /usr/local/bin
sudo cp node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter
Create a systemd service file so Node Exporter runs automatically on boot:
sudo tee /etc/systemd/system/node_exporter.service <
Verify that Node Exporter is working correctly:
curl http://localhost:9100/metrics | head -20
Step 3: Install Prometheus
Prometheus is the time-series database that stores all metrics and runs on port 9090.
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v2.52.0/prometheus-2.52.0.linux-amd64.tar.gz
tar xvf prometheus-2.52.0.linux-amd64.tar.gz
sudo mkdir /etc/prometheus /var/lib/prometheus
sudo cp prometheus-2.52.0.linux-amd64/prometheus /usr/local/bin/
sudo cp prometheus-2.52.0.linux-amd64/promtool /usr/local/bin/
sudo cp -r prometheus-2.52.0.linux-amd64/consoles /etc/prometheus
sudo cp -r prometheus-2.52.0.linux-amd64/console_libraries /etc/prometheus
sudo chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
sudo chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtool
Create Prometheus main configuration file:
sudo tee /etc/prometheus/prometheus.yml <
Create a systemd service for Prometheus:
sudo tee /etc/systemd/system/prometheus.service <
--storage.tsdb.retention.time=30d). You can adjust this based on your available disk space.Step 4: Install Grafana
Grafana runs on port 3000 and is installed via the official apt repository:
sudo apt install -y apt-transport-https software-properties-common wget
wget -q -O - https://apt.grafana.com/gpg.key | sudo apt-key add -
echo "deb https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt update
sudo apt install grafana -y
sudo systemctl daemon-reload
sudo systemctl enable grafana-server
sudo systemctl start grafana-server
sudo systemctl status grafana-server
Access Grafana through your browser: http://YOUR_VPS_IP:3000
First login credentials: username admin / password admin (the system will force you to change the password immediately)
Step 5: Connect Grafana to Prometheus
- Go to menu Connections → Data Sources
- Click Add data source and select Prometheus
- Enter URL:
http://localhost:9090 - Click Save & Test — you should see "Data source is working"
Step 6: Import Ready-Made Dashboard
No need to create a dashboard from scratch. Grafana has free community dashboards available:
- Go to Dashboards → Import
- Enter ID
1860(Node Exporter Full — the most popular dashboard) - Click Load and select the Prometheus data source you just created
- Click Import
Once imported, you'll immediately see a dashboard displaying CPU Usage, Memory Usage, Disk I/O, Network Traffic, and over 50 other metrics in real-time.
13978 (Node Exporter for Prometheus Dashboard), 405 (Basic Node Exporter)Step 7: Configure Alert Rules
Alerts help you know immediately when your server has issues, such as CPU exceeding 80% or disk dropping below 10%.
Create Alert Rule for High CPU
- Go to Alerting → Alert Rules → New alert rule
- Set name:
High CPU Usage - Enter query in Expression A:
100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
- Set condition:
IS ABOVE 80(alert when CPU exceeds 80%) - Set Evaluate every:
1m, For:5m(must be high for 5 minutes continuously before alerting)
Alerts for Memory and Disk
# Memory Usage exceeds 90%
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
# Disk has less than 10% free
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100 < 10
Step 8: Configure Notification Channels (Email/LINE)
Grafana can send alerts through multiple channels: Email, Slack, LINE Notify, Telegram, PagerDuty, and more.
# Configure SMTP for sending Email in /etc/grafana/grafana.ini
sudo nano /etc/grafana/grafana.ini
# Find the [smtp] section and edit:
[smtp]
enabled = true
host = smtp.gmail.com:587
user = [email protected]
password = your-app-password
from_address = [email protected]
from_name = Grafana Alert
sudo systemctl restart grafana-server
Then go to Alerting → Contact Points → Add contact point to add Email or Webhook notification channels.
Step 9: Security — Close Unnecessary Ports
# Allow only port 3000 (Grafana) for public access
# Close ports 9090 and 9100 from public internet
sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 3000/tcp
sudo ufw deny 9090/tcp
sudo ufw deny 9100/tcp
sudo ufw enable
Or if you need to access Prometheus from a specific IP:
sudo ufw allow from YOUR_HOME_IP to any port 9090
sudo ufw allow from YOUR_HOME_IP to any port 9100
Step 10: Set Up Reverse Proxy with Nginx (Recommended)
Instead of exposing port 3000 directly, place Nginx in front with SSL:
sudo apt install nginx -y
sudo tee /etc/nginx/sites-available/grafana <
Then use Certbot to add SSL:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d grafana.yourdomain.com
Post-Installation Checklist
- Node Exporter is running and
curl localhost:9100/metricsresponds - Prometheus successfully scrapes the node job (check in Status → Targets)
- Grafana login works and data source test passes
- Dashboard displays real-time data for all metrics (CPU/RAM/Disk/Network)
- Alert rules are configured and contact points receive test notifications
- Ports 9090 and 9100 are closed from public internet
- Nginx reverse proxy with SSL is working correctly
Quality VPS and Hosting for Monitoring Systems
A good monitoring system requires stable VPS with high uptime. asiagb provides Linux VPS in Thailand and Singapore with 99.9% SLA and 24/7 Thai language support. Perfect for both monitoring servers and production workloads.
Before adding new metric endpoints, check domain health first using dnsxray.com — verify SSL, DNS, Security Headers, and Uptime for free on a single page. This helps ensure your endpoint is ready before scraping.
Summary: Professional Monitoring with Grafana + Prometheus
Once you've completed all the steps, you'll have a production-grade monitoring system that:
- Collects metrics every 15 seconds with 30 days of history
- Displays real-time dashboards accessible from any device via browser
- Automatically alerts you when CPU/RAM/Disk exceed thresholds
- Maintains security with firewall + SSL + reverse proxy
Recommended next steps include adding exporters for MySQL, Nginx, or your custom applications, as well as setting up Alertmanager for more complex alert routing. This Grafana + Prometheus system is highly scalable — suitable for single VPS through clusters of dozens of machines.
Verify Grafana + Prometheus is Working Correctly
# Verify Node Exporter is sending metrics
curl -s http://localhost:9100/metrics | grep node_cpu_seconds_total | head -3
# Verify Prometheus is healthy and scrape targets succeed
curl -s http://localhost:9090/-/healthy
curl -s "http://localhost:9090/api/v1/targets" | python3 -m json.tool | grep '"health"'
# Verify Grafana is responding
curl -s http://localhost:3000/api/health | python3 -m json.tool
# View current VPS metrics via Prometheus query
curl -s "http://localhost:9090/api/v1/query?query=100-(avg(rate(node_cpu_seconds_total{mode='idle'}[5m]))*100)" \
| python3 -m json.tool | grep value
Common Issues & Troubleshooting
Prometheus targets show "DOWN" — Node Exporter not being scraped
Node Exporter may have stopped running or your Prometheus config is incorrect.
# Check node_exporter service
sudo systemctl status node_exporter
# Verify port 9100 is open
ss -tlnp | grep 9100
# Test curl directly
curl http://localhost:9100/metrics | head -5
# Check Prometheus config for correct target
cat /etc/prometheus/prometheus.yml | grep -A5 "job_name"
Grafana cannot connect to Prometheus — "Data source connection error"
The Prometheus URL in your Grafana data source is incorrect.
# Check if Prometheus is running
sudo systemctl status prometheus
# Test the endpoint Grafana will use
curl http://localhost:9090/api/v1/query?query=up
# Correct URL in Grafana data source:
# http://localhost:9090 (if Grafana and Prometheus are on the same machine)
Dashboard shows "No data" even though Prometheus targets are UP
Time range doesn't match or query labels don't match the actual instance.
# Check in Prometheus UI first:
# Visit http://VPS_IP:9090/graph and run this query:
up{job="node"}
# If you see results but Grafana doesn't, try:
# 1. Change Time range in Grafana to "Last 1 hour"
# 2. Check $instance variable in dashboard filtering
# 3. Refresh datasource in Grafana → Connections
Alerts not sending even though metrics exceed threshold
Alert state must stay in "Firing" for the duration specified in "For" before sending. Contact point must also be configured correctly.
# Check in Grafana:
# Alerting → Alert Rules → check State column
# If State is "Pending", waiting for "For" duration to complete
# If State is "Normal", metric hasn't actually exceeded threshold
# Test contact point by clicking "Test" in:
# Alerting → Contact Points → Edit → Send test notification
Prometheus consuming too much RAM/Disk
Metric data accumulates over time. Adjust retention policy or scrape interval.
# Check Prometheus disk usage
du -sh /var/lib/prometheus/
# Reduce retention time (set in systemd service or flag)
# Edit /etc/systemd/system/prometheus.service
# Add: --storage.tsdb.retention.time=15d
# Reduce scrape interval if you don't need fine resolution
# In prometheus.yml:
global:
scrape_interval: 60s # change from 15s to 60s
Frequently Asked Questions
How long does Prometheus store data?
Default is 15 days. In this article, we set it to 30 days. You can adjust with the --storage.tsdb.retention.time flag or limit by disk size with --storage.tsdb.retention.size=10GB. For a 2GB RAM VPS monitoring a single machine for 30 days, expect about 1-3 GB disk usage.
How do I monitor multiple VPS machines?
Install Node Exporter on every machine you want to monitor, then add targets to prometheus.yml on your single Prometheus server. Prometheus will scrape every target every 15 seconds. You don't need to install Prometheus on every machine — just one is enough.
How are Grafana Cloud and Self-hosted different?
Grafana Cloud has a Free Tier (10,000 metrics series, 50GB logs/month) with no server maintenance required, but your data is hosted on Grafana Labs' infrastructure. Self-hosted gives you full control, data stays on your VPS, and no metric limits — ideal for production requiring data privacy or retention longer than 30 days.