Grafana and Prometheus are the industry-standard open-source monitoring stack — Prometheus scrapes metrics from your applications and infrastructure, stores them as time-series data, and Grafana visualises them in dashboards. Deployed on a Hong Kong VPS, this stack gives you real-time visibility into CPU, memory, disk I/O, network throughput, Nginx request rates, MySQL query performance, and any application-level metric your team cares about.
Architecture
[Your Applications + Exporters] → [Prometheus] → [Grafana Dashboards]
- node_exporter (system) scrapes visualises
- nginx-exporter (Nginx) stores alerts
- mysqld_exporter (MySQL) queries
- blackbox_exporter (HTTP/TCP)
Step 1: Install Prometheus
apt update && apt upgrade -y
# Create prometheus user (never run as root)
useradd --no-create-home --shell /bin/false prometheus
mkdir -p /etc/prometheus /var/lib/prometheus
# Download Prometheus
PROM_VERSION="2.52.0"
wget https://github.com/prometheus/prometheus/releases/download/v${PROM_VERSION}/prometheus-${PROM_VERSION}.linux-amd64.tar.gz
tar xzf prometheus-${PROM_VERSION}.linux-amd64.tar.gz
cp prometheus-${PROM_VERSION}.linux-amd64/prometheus /usr/local/bin/
cp prometheus-${PROM_VERSION}.linux-amd64/promtool /usr/local/bin/
cp -r prometheus-${PROM_VERSION}.linux-amd64/consoles /etc/prometheus/
cp -r prometheus-${PROM_VERSION}.linux-amd64/console_libraries /etc/prometheus/
chown -R prometheus:prometheus /etc/prometheus /var/lib/prometheus
chown prometheus:prometheus /usr/local/bin/prometheus /usr/local/bin/promtoolConfigure Prometheus
cat > /etc/prometheus/prometheus.yml << 'EOF'
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets: ['localhost:9093']
rule_files:
- "alert_rules.yml"
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
- job_name: 'nginx'
static_configs:
- targets: ['localhost:9113']
- job_name: 'mysql'
static_configs:
- targets: ['localhost:9104']
- job_name: 'blackbox_http'
metrics_path: /probe
params:
module: [http_2xx]
static_configs:
- targets:
- https://yourdomain.com
- https://api.yourdomain.com/health
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115
EOFCreate Systemd Service
cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus Monitoring
After=network.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/ \
--storage.tsdb.retention.time=30d \
--web.listen-address=127.0.0.1:9090 \
--web.console.templates=/etc/prometheus/consoles \
--web.console.libraries=/etc/prometheus/console_libraries
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now prometheusStep 2: Install Node Exporter (System Metrics)
NODE_VERSION="1.8.1"
wget https://github.com/prometheus/node_exporter/releases/download/v${NODE_VERSION}/node_exporter-${NODE_VERSION}.linux-amd64.tar.gz
tar xzf node_exporter-${NODE_VERSION}.linux-amd64.tar.gz
cp node_exporter-${NODE_VERSION}.linux-amd64/node_exporter /usr/local/bin/
cat > /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=prometheus
ExecStart=/usr/local/bin/node_exporter \
--collector.systemd \
--collector.processes
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now node_exporterStep 3: Install MySQL Exporter
# Create MySQL user for monitoring (read-only)
mysql -u root -p << 'SQL' CREATE USER 'prometheus'@'localhost' IDENTIFIED BY 'MonitorPassword!'; GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'prometheus'@'localhost'; FLUSH PRIVILEGES; SQL MYSQL_EXP_VERSION="0.15.1" wget https://github.com/prometheus/mysqld_exporter/releases/download/v${MYSQL_EXP_VERSION}/mysqld_exporter-${MYSQL_EXP_VERSION}.linux-amd64.tar.gz tar xzf mysqld_exporter-${MYSQL_EXP_VERSION}.linux-amd64.tar.gz cp mysqld_exporter-${MYSQL_EXP_VERSION}.linux-amd64/mysqld_exporter /usr/local/bin/ cat > /etc/.mysqld_exporter.cnf << 'EOF' [client] user=prometheus password=MonitorPassword! EOF chmod 600 /etc/.mysqld_exporter.cnf cat > /etc/systemd/system/mysqld_exporter.service << 'EOF'
[Unit]
Description=MySQL Exporter for Prometheus
After=network.target
[Service]
User=prometheus
ExecStart=/usr/local/bin/mysqld_exporter \
--config.my-cnf=/etc/.mysqld_exporter.cnf
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now mysqld_exporterStep 4: Install Nginx Exporter
# Enable nginx stub_status endpoint (add to nginx.conf server block)
cat >> /etc/nginx/conf.d/stub_status.conf << 'EOF' server { listen 127.0.0.1:8080; location /stub_status { stub_status; } } EOF nginx -t && systemctl reload nginx NGINX_EXP_VERSION="1.3.0" wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v${NGINX_EXP_VERSION}/nginx-prometheus-exporter_${NGINX_EXP_VERSION}_linux_amd64.tar.gz tar xzf nginx-prometheus-exporter_*.tar.gz cp nginx-prometheus-exporter /usr/local/bin/ cat > /etc/systemd/system/nginx_exporter.service << 'EOF'
[Unit]
Description=Nginx Prometheus Exporter
After=network.target
[Service]
User=prometheus
ExecStart=/usr/local/bin/nginx-prometheus-exporter \
-nginx.scrape-uri http://127.0.0.1:8080/stub_status
Restart=always
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now nginx_exporterStep 5: Install Grafana
apt install -y apt-transport-https software-properties-common
wget -q -O /usr/share/keyrings/grafana.key https://apt.grafana.com/gpg.key
echo "deb [signed-by=/usr/share/keyrings/grafana.key] https://apt.grafana.com stable main" \
| tee /etc/apt/sources.list.d/grafana.list
apt update && apt install -y grafana
systemctl enable --now grafana-serverExpose via Nginx
cat > /etc/nginx/sites-available/grafana << 'EOF'
server {
listen 443 ssl http2;
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://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
EOF
ln -s /etc/nginx/sites-available/grafana /etc/nginx/sites-enabled/
certbot --nginx -d grafana.yourdomain.com
nginx -t && systemctl reload nginxStep 6: Configure Grafana Dashboards
Visit https://grafana.yourdomain.com. Default credentials: admin / admin (change immediately).
Add Prometheus Data Source
Configuration → Data Sources → Add data source → Prometheus
- URL:
http://localhost:9090 - Click Save & Test
Import Community Dashboards
Dashboards → Import — enter these dashboard IDs:
- 1860 — Node Exporter Full (system CPU, memory, disk, network)
- 7362 — MySQL Overview
- 12708 — Nginx Exporter
- 7587 — Blackbox Exporter (HTTP uptime)
Each dashboard imports pre-built panels with sensible defaults — you have production-quality monitoring within minutes of import.
Step 7: Configure Alerting
cat > /etc/prometheus/alert_rules.yml << 'EOF' groups: - name: vps_alerts rules: - alert: HighCPU expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 85
for: 5m
annotations:
summary: "High CPU on {{ $labels.instance }}"
description: "CPU usage is {{ $value }}%"
- alert: HighMemory
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
for: 5m
annotations:
summary: "High memory usage on {{ $labels.instance }}"
- alert: DiskSpaceLow
expr: node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs"} / node_filesystem_size_bytes * 100 < 15
for: 10m
annotations:
summary: "Disk space below 15% on {{ $labels.instance }}"
- alert: SiteDown
expr: probe_success == 0
for: 2m
annotations:
summary: "Site {{ $labels.instance }} is DOWN"
EOFConnect Alertmanager to send notifications to Telegram, Slack, or email when rules fire. The Grafana UI also supports alert rules natively via Alerting → Alert Rules with direct channel notifications.
Conclusion
A Grafana + Prometheus stack on your Hong Kong VPS provides complete observability — system resources, web server throughput, database performance, and external uptime checks — all from a single dashboard accessible from anywhere. The 30-day metric retention gives you historical context for capacity planning, and the alert rules catch problems before users notice them.
Monitor your infrastructure: Browse Server.HK Hong Kong VPS plans — a dedicated 2 GB VPS for the monitoring stack keeps it isolated from production workloads.