Introduction
Prometheus est devenu le standard de facto pour le monitoring : utilisé par SoundCloud (ses créateurs), CNCF, Kubernetes natif, et 90% des startups tech. Le combo gagnant :
- Prometheus : scrape les métriques toutes les 15s, stockage TSDB efficient
- Node Exporter : agent système (CPU, RAM, disque, réseau) sur chaque VPS
- Grafana : visualisation et alerting
- Alertmanager : routing des alertes (email, Discord, Slack)
Bénéfices vs des outils SaaS payants (Datadog, New Relic) :
- Gratuit, self-hosted, chez vous
- Pas de limite de métriques
- Données souveraines
Prérequis
- 1 VPS "central" pour Prometheus + Grafana (2 Go RAM)
- N VPS à monitorer (Node Exporter)
- Docker sur le VPS central
- Réseau entre VPS (WireGuard recommandé)
Étape 1 : Architecture
┌──────────────────┐ ┌──────────────────┐
│ VPS Web 1 │ │ VPS DB │
│ + Node Exporter │ │ + Node Exporter │
│ + Nginx Exporter│ │ + MySQL Exporter│
└────────┬─────────┘ └────────┬─────────┘
│ │
└──────────┬──────────┘
│
┌────────▼────────┐
│ VPS Central │
│ ┌───────────┐ │
│ │ Prometheus│ │
│ └───────────┘ │
│ ┌───────────┐ │
│ │ Grafana │ │
│ └───────────┘ │
│ ┌───────────┐ │
│ │Alertmanager│ │
│ └───────────┘ │
└─────────────────┘
Étape 2 : Déployer la stack centrale
sudo mkdir -p /opt/monitoring
cd /opt/monitoring
sudo nano docker-compose.yml
services:
prometheus:
image: prom/prometheus:latest
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--storage.tsdb.retention.time=90d'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
networks:
- monitoring
grafana:
image: grafana/grafana:latest
container_name: grafana
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=UnMotDePasseFort
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana_data:/var/lib/grafana
networks:
- monitoring
depends_on:
- prometheus
alertmanager:
image: prom/alertmanager:latest
container_name: alertmanager
restart: unless-stopped
ports:
- "9093:9093"
volumes:
- ./alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
networks:
- monitoring
node_exporter:
image: prom/node-exporter:latest
container_name: node_exporter
restart: unless-stopped
pid: host
network_mode: host
volumes:
- /:/host:ro,rslave
command:
- '--path.rootfs=/host'
volumes:
prometheus_data:
grafana_data:
networks:
monitoring:
Étape 3 : Config Prometheus
sudo nano /opt/monitoring/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- "alerts.yml"
scrape_configs:
# Prometheus lui-même
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
# VPS central (Node Exporter)
- job_name: 'node_central'
static_configs:
- targets: ['host.docker.internal:9100']
labels:
host: 'srv-central'
# VPS Web 1
- job_name: 'node_web1'
static_configs:
- targets: ['10.66.66.2:9100']
labels:
host: 'srv-web-01'
# VPS Web 2
- job_name: 'node_web2'
static_configs:
- targets: ['10.66.66.3:9100']
labels:
host: 'srv-web-02'
# VPS DB
- job_name: 'node_db'
static_configs:
- targets: ['10.66.66.4:9100']
labels:
host: 'srv-db-01'
# Nginx Exporter
- job_name: 'nginx'
static_configs:
- targets: ['10.66.66.2:9113']
labels:
host: 'srv-web-01'
# MySQL Exporter
- job_name: 'mysql'
static_configs:
- targets: ['10.66.66.4:9104']
labels:
host: 'srv-db-01'
Étape 4 : Règles d'alerte de base
sudo nano /opt/monitoring/alerts.yml
groups:
- name: system_alerts
interval: 30s
rules:
- alert: HighCPU
expr: 100 - (avg by(host) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90
for: 5m
labels:
severity: warning
annotations:
summary: "CPU > 90% sur {{ $labels.host }}"
description: "CPU à {{ $value }}% depuis 5 minutes."
- alert: HighMemory
expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100 > 90
for: 5m
labels:
severity: warning
annotations:
summary: "RAM > 90% sur {{ $labels.host }}"
- alert: DiskFull
expr: (node_filesystem_size_bytes{mountpoint="/"} - node_filesystem_avail_bytes{mountpoint="/"}) / node_filesystem_size_bytes{mountpoint="/"} * 100 > 90
for: 5m
labels:
severity: critical
annotations:
summary: "Disque > 90% sur {{ $labels.host }}"
- alert: NodeDown
expr: up{job=~"node_.*"} == 0
for: 2m
labels:
severity: critical
annotations:
summary: "Host {{ $labels.host }} est DOWN"
- alert: HighLoad
expr: node_load5 > 4
for: 10m
labels:
severity: warning
annotations:
summary: "Load > 4 sur {{ $labels.host }}"
Étape 5 : Config Alertmanager (Discord/email)
sudo nano /opt/monitoring/alertmanager.yml
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'host']
group_wait: 30s
group_interval: 5m
repeat_interval: 12h
receiver: 'discord'
receivers:
- name: 'discord'
webhook_configs:
- url: 'https://discord.com/api/webhooks/VOTRE_WEBHOOK'
send_resolved: true
- name: 'email'
email_configs:
- to: '[email protected]'
from: '[email protected]'
smarthost: 'smtp.example.com:587'
auth_username: '[email protected]'
auth_password: 'password'
require_tls: true
Étape 6 : Démarrer la stack
sudo docker compose up -d
sudo docker compose ps
Vérifiez :
- Prometheus : http://localhost:9090
- Grafana : http://localhost:3000 (via SSH tunnel)
- Alertmanager : http://localhost:9093
Étape 7 : Installer Node Exporter sur chaque VPS source
Sur chaque VPS à monitorer :
# Télécharger
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
sudo mv node_exporter-1.8.1.linux-amd64/node_exporter /usr/local/bin/
sudo chown root:root /usr/local/bin/node_exporter
# User dédié
sudo useradd --no-create-home --shell /bin/false node_exporter
sudo chown node_exporter:node_exporter /usr/local/bin/node_exporter
Service systemd :
sudo nano /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.systemd \
--collector.processes \
--web.listen-address=0.0.0.0:9100
Restart=always
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter
Testez :
curl http://localhost:9100/metrics | head -30
Doit afficher les métriques node_cpu_seconds_total, node_memory_MemTotal_bytes, etc.
Étape 8 : Sécuriser Node Exporter
⚠️ Ne pas exposer le port 9100 publiquement (révèle de la donnée sensible). Solutions :
- WireGuard entre VPS (recommandé)
- UFW :
sudo ufw allow from IP_VPS_CENTRAL to any port 9100 - Reverse proxy avec auth basique sur le central
Étape 9 : Ajouter Grafana
Tunnel SSH :
ssh -L 3000:127.0.0.1:3000 user@IP_VPS_CENTRAL
http://localhost:3000 → admin / UnMotDePasseFort
Datasource Prometheus
- Configuration → Data sources → Add data source
- Prometheus
- URL :
http://prometheus:9090 - Save & test
Dashboard Node Exporter
- Dashboards → Import
- ID : 1860 (Node Exporter Full, le plus populaire)
- Datasource : Prometheus
- Import
Vous obtenez instantanément CPU, RAM, disque, réseau, load, processus pour tous vos VPS.
Étape 10 : Exporters additionnels
Selon vos services :
Nginx Exporter
docker run -d \
--restart unless-stopped \
--name nginx-exporter \
-p 9113:9113 \
nginx/nginx-prometheus-exporter \
-nginx.scrape-uri=http://localhost/nginx_status
Activez stub_status dans Nginx :
server {
listen 127.0.0.1:80;
location /nginx_status {
stub_status;
allow 127.0.0.1;
deny all;
}
}
Dashboard Grafana : ID 12708.
MySQL Exporter
docker run -d \
--restart unless-stopped \
--name mysql-exporter \
-p 9104:9104 \
-e DATA_SOURCE_NAME='exporter:password@(localhost:3306)/' \
prom/mysqld-exporter
Créez un user MySQL dédié :
CREATE USER 'exporter'@'localhost' IDENTIFIED BY 'password' WITH MAX_USER_CONNECTIONS 3;
GRANT PROCESS, REPLICATION CLIENT, SELECT ON *.* TO 'exporter'@'localhost';
FLUSH PRIVILEGES;
Dashboard Grafana : ID 7362.
Redis Exporter
docker run -d \
--restart unless-stopped \
--name redis-exporter \
-p 9121:9121 \
oliver006/redis_exporter \
--redis.addr=redis://localhost:6379 \
--redis.password=YOUR_REDIS_PASSWORD
Dashboard : ID 763.
Blackbox Exporter (HTTP/TCP probes)
Pour monitorer des URLs externes (uptime de votre site) :
docker run -d \
--name blackbox-exporter \
-p 9115:9115 \
prom/blackbox-exporter
Étape 11 : Dashboards recommandés
Importer dans Grafana via Dashboards → Import :
- 1860 : Node Exporter Full
- 12708 : Nginx Exporter
- 7362 : MySQL Overview
- 763 : Redis Dashboard
- 13639 : Loki + Promtail (logs)
- 893 : Docker and Host
- 9628 : PostgreSQL
Étape 12 : Alerting via Grafana (alternative à Alertmanager)
Grafana 10+ a son propre alerting natif :
- Alerting → Alert rules → New alert rule
- Query :
100 - (avg by(host) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 90 - Add contact point : Discord, Slack, Telegram, etc.
- Notification policy : groupage, throttling
Plus pratique qu'Alertmanager pour des setups simples.
Dépannage
Targets en DOWN dans Prometheus
http://localhost:9090/targets → vérifiez la connectivité :
curl http://IP_VPS:9100/metrics
Causes : firewall, IP fausse dans prometheus.yml, node_exporter pas démarré.
Pas de métriques dans Grafana
Vérifiez la datasource (Configuration → Data sources → test). Puis dans Explore, testez up{job="node_web1"}.
Prometheus bouffe trop d'espace
Limitez la rétention :
command:
- '--storage.tsdb.retention.time=30d' # au lieu de 90d
Alertes ne sont pas envoyées
sudo docker compose logs alertmanager
Testez le webhook Discord manuellement :
curl -X POST -H "Content-Type: application/json" \
-d '{"content": "test"}' \
https://discord.com/api/webhooks/VOTRE_WEBHOOK
Commandes utiles
# État des targets
curl http://localhost:9090/api/v1/targets
# Requêter Prometheus en CLI
curl "http://localhost:9090/api/v1/query?query=up"
# Reload de la config sans restart
curl -X POST http://localhost:9090/-/reload
# Tester les alertes
curl http://localhost:9090/api/v1/alerts
# Vérifier la config Prometheus
sudo docker run --rm -v $(pwd)/prometheus.yml:/etc/prometheus/prometheus.yml \
prom/prometheus promtool check config /etc/prometheus/prometheus.yml
# Vérifier les règles d'alerte
sudo docker run --rm -v $(pwd)/alerts.yml:/etc/prometheus/alerts.yml \
prom/prometheus promtool check rules /etc/prometheus/alerts.yml
Conclusion
Avec cette stack vous avez :
- Monitoring CPU/RAM/disque/réseau/charge sur tous vos VPS
- Alerting automatique en cas de problème
- Dashboards visuels pour debug rapide
- Stockage long terme des métriques (90 jours par défaut)
Pour aller plus loin :
- Ajoutez Loki pour les logs (déjà couvert dans un autre tuto)
- Ajoutez Tempo pour le tracing distribué
- Migrez vers Thanos ou Cortex pour de la haute dispo Prometheus
- Utilisez Prometheus Operator si vous passez à Kubernetes
Ressources
- Site officiel : https://prometheus.io
- Documentation Prometheus : https://prometheus.io/docs/
- Grafana dashboards : https://grafana.com/grafana/dashboards/
- Tuto VeryCloud — Logs Loki + Promtail :
/docs/article/loki-promtail - Tuto VeryCloud — Docker Compose prod :
/docs/article/docker-compose-prod


















