Grafana + Prometheus: Monitoring Stack
Prometheus collects metrics from the server, Grafana visualizes them in dashboards. Together they form the most widespread monitoring stack in Linux environments.
Architecture
VPS → node_exporter → Prometheus → Grafana → Browser
↓
Alertmanager → Email/Telegram
- node_exporter: exports system metrics (CPU, RAM, disk, network)
- Prometheus: scrapes and saves metrics over time
- Grafana: web dashboard to visualize data
Install node_exporter
# Latest version from https://github.com/prometheus/node_exporter/releases
NODE_EXPORTER_VERSION="1.8.2"
cd /tmp
wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
tar xvf node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz
mv node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter /usr/local/bin/
systemd service for node_exporter
useradd --no-create-home --shell /bin/false node_exporter
cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User=node_exporter
Group=node_exporter
ExecStart=/usr/local/bin/node_exporter \
--web.listen-address=":9100" \
--collector.systemd \
--collector.processes
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now node_exporter
Verify: curl http://localhost:9100/metrics | head -20
Install Prometheus
PROMETHEUS_VERSION="2.53.0"
cd /tmp
wget https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
tar xvf prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz
mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/prometheus /usr/local/bin/
mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/promtool /usr/local/bin/
mkdir -p /etc/prometheus /var/lib/prometheus
mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/consoles /etc/prometheus/
mv prometheus-${PROMETHEUS_VERSION}.linux-amd64/console_libraries /etc/prometheus/
useradd --no-create-home --shell /bin/false prometheus
chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
Prometheus configuration
cat > /etc/prometheus/prometheus.yml << 'EOF'
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"]
labels:
instance: "my-vps"
env: "production"
EOF
systemd service for Prometheus
cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
After=network.target
[Service]
User=prometheus
Group=prometheus
ExecStart=/usr/local/bin/prometheus \
--config.file=/etc/prometheus/prometheus.yml \
--storage.tsdb.path=/var/lib/prometheus \
--storage.tsdb.retention.time=30d \
--web.listen-address=":9090" \
--web.enable-lifecycle
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now prometheus
Verify: curl http://localhost:9090/-/healthy
Install Grafana
# Add Grafana repository
apt install -y apt-transport-https software-properties-common
wget -q -O - https://packages.grafana.com/gpg.key | gpg --dearmor > /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://packages.grafana.com/oss/deb stable main" > /etc/apt/sources.list.d/grafana.list
apt update
apt install -y grafana
systemctl enable --now grafana-server
Grafana is now available at http://SERVER_IP:3000.
Default login: admin / admin (change the password immediately on first access).
Secure access to Grafana
Grafana should not be exposed directly. Two options:
Option 1: SSH tunnel (local development)
ssh -L 3000:localhost:3000 root@SERVER_IP
# Then visit http://localhost:3000
Option 2: Nginx reverse proxy with SSL
server {
listen 443 ssl;
server_name grafana.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/grafana.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/grafana.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Add Prometheus as datasource in Grafana
- Go to Connections → Data Sources → Add data source
- Choose Prometheus
- URL: http://localhost:9090
- Click Save & Test
Ready-to-use dashboards
Import the official dashboard for node_exporter:
Other useful dashboards:
- Dashboards → Import
- ID: 1860 (Node Exporter Full: most complete)
- Select the Prometheus datasource
- Import
- 3662: Node Exporter (simpler)
- 14282: Prometheus 2.0 Stats
- 7362: cAdvisor (for Docker)
Useful PromQL queries
# CPU usage %
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# Available RAM in GB
node_memory_MemAvailable_bytes / 1024^3
# Disk usage %
(1 - node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100
# Network traffic in Mbps
rate(node_network_transmit_bytes_total{device="eth0"}[5m]) * 8 / 1024^2
# Load average 1m
node_load1
Alerting on Telegram
# Create a Telegram bot: talk to @BotFather → /newbot
# Get the TOKEN and CHAT_ID
nano /etc/grafana/grafana.ini
[alerting]
enabled = true
[unified_alerting]
enabled = true
In Grafana: Alerting → Contact points → Add contact point → Telegram
Enter the BOT_TOKEN and CHAT_ID. Then create alert rules on panels.
Monitor multiple servers
Add other servers to prometheus.yml:
scrape_configs:
- job_name: "node"
static_configs:
- targets:
- "localhost:9100" # main server
- "10.0.0.2:9100" # secondary server (private network)
- "1.2.3.4:9100" # another VPS (expose only if protected)
labels:
env: "production"
If a server is not directly reachable from Prometheus (NAT, firewall), use Pushgateway: the server sends metrics instead of being scraped.
Related articles
