Il y a quelques mois, Nextcloud a arrêté de synchroniser pour toute la famille pendant 48h. Personne ne l’a remarqué immédiatement – le service ne tombait pas, il se connectait, mais les uploads échouaient silencieusement. Ce n’est que quand ma femme a voulu retrouver des photos d’un week-end qu’on a découvert qu’elles n’avaient jamais été sauvegardées.
La cause : le disque de données Nextcloud était plein. 0 octet disponible. Pas d’alerte, pas de log visible depuis l’interface. Juste un service qui tombait en silence.
Depuis, j’ai une stack monitoring complète. Accessible sur hubble.arewel.com (le nom de mon stack d’observabilité interne). Ce guide documente comment je l’ai mise en place.
Architecture
Nœud Proxmox (192.168.1.10)
├── pve-exporter :9221 ← métriques Proxmox (VMs, LXC, stockage, nœud)
│
LXC 150 Pi-hole → nodeexporter :9100
LXC 162 Nextcloud → nodeexporter :9100
LXC 163 Gitea → nodeexporter :9100
LXC 164 Jellyfin → nodeexporter :9100
VM 300 HAOS → nodeexporter :9100 (via Prometheus integration HAOS)
...
│
└── LXC 120 Prometheus (192.168.30.120)
└── LXC 121 Grafana (192.168.30.121)
└── AlertManager → Telegram
Prometheus scrape toutes les sources toutes les 30 secondes. Grafana interroge Prometheus. AlertManager évalue les règles d’alerte et pousse vers Telegram.
Déployer Prometheus
Créer le LXC 120 en VLAN 30 (réseau serveurs) :
pct create 120 local:vztmpl/debian-12-standard12.7-1amd64.tar.zst
--hostname prometheus
--memory 512
--cores 1
--net0 name=eth0,bridge=vmbr0,tag=30,ip=192.168.30.120/24,gw=192.168.30.1
--storage rpool
--rootfs rpool:10
--unprivileged 1
--onboot 1
pct start 120
pct enter 120
Installer Prometheus :
PROMETHEUSVERSION="2.52.0"
cd /tmp
wget -q https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUSVERSION}/prometheus-${PROMETHEUSVERSION}.linux-amd64.tar.gz
tar xzf prometheus-${PROMETHEUSVERSION}.linux-amd64.tar.gz
install -m 755 prometheus-${PROMETHEUSVERSION}.linux-amd64/prometheus /usr/local/bin/
install -m 755 prometheus-${PROMETHEUSVERSION}.linux-amd64/promtool /usr/local/bin/
useradd --no-create-home --shell /bin/false prometheus
mkdir -p /etc/prometheus /var/lib/prometheus
chown prometheus:prometheus /var/lib/prometheus
Créer la configuration :
global:
scrapeinterval: 30s
evaluationinterval: 30s
externallabels:
homelab: 'ms01'
rulefiles:
- /etc/prometheus/rules/.yml
alerting:
alertmanagers:
- staticconfigs:
- targets: ['localhost:9093']
scrapeconfigs:
- jobname: 'proxmox-node'
staticconfigs:
- targets: ['192.168.1.10:9221']
metricspath: /pve
params:
target: ['localhost']
module: ['default']
- jobname: 'nodes'
staticconfigs:
- targets:
- '192.168.1.150:9100' # Pi-hole LXC
- '192.168.30.160:9100' # NPM
- '192.168.30.161:9100' # Vaultwarden
- '192.168.30.162:9100' # Nextcloud
- '192.168.30.163:9100' # Gitea
- '192.168.30.164:9100' # Jellyfin
- '192.168.30.165:9100' # Immich
- '192.168.30.166:9100' # Paperless
- '192.168.30.50:9100' # PBS VM
- '192.168.30.120:9100' # Prometheus lui-même
- '192.168.30.121:9100' # Grafana
- jobname: 'pihole'
staticconfigs:
- targets: ['192.168.1.150:9617'] # pihole-exporter
Créer le service systemd :
cat > /etc/systemd/system/prometheus.service << 'EOF'
[Unit]
Description=Prometheus
After=network.target
[Service]
User=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
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now prometheus
Prometheus est accessible sur http://192.168.30.120:9090. Vérifier que les targets sont UP dans Status > Targets.
Installer nodeexporter sur chaque machine
nodeexporter est un binaire unique qui expose les métriques système (CPU, RAM, disque, réseau) sur le port 9100. Il doit tourner sur chaque VM et LXC à monitorer.
Script d'installation à appliquer dans chaque container :
NODEEXPORTERVERSION="1.8.1"
cd /tmp
wget -q https://github.com/prometheus/nodeexporter/releases/download/v${NODEEXPORTERVERSION}/nodeexporter-${NODEEXPORTERVERSION}.linux-amd64.tar.gz
tar xzf nodeexporter-${NODEEXPORTERVERSION}.linux-amd64.tar.gz
install -m 755 nodeexporter-${NODEEXPORTERVERSION}.linux-amd64/nodeexporter /usr/local/bin/
useradd --no-create-home --shell /bin/false nodeexporter
cat > /etc/systemd/system/nodeexporter.service << 'EOF'
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=nodeexporter
ExecStart=/usr/local/bin/nodeexporter
--web.listen-address=:9100
--collector.filesystem.mount-points-exclude='^/(dev|proc|run|sys|tmp)($|/)'
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now nodeexporter
Pour l'installer sur plusieurs machines rapidement, j'utilise un one-liner depuis le nœud Proxmox :
for CT in 150 160 161 162 163 164 165 166 167; do
echo "=== LXC $CT ==="
pct exec $CT -- bash -c "$(cat /root/install-node-exporter.sh)"
done
pve-exporter : métriques Proxmox natives
pve-exporter interroge l'API Proxmox et expose les métriques des VMs, LXC, nœuds et stockages. Il tourne directement sur le nœud Proxmox.
# Sur le nœud Proxmox (pas dans un LXC)
apt install -y python3-pip python3-venv
python3 -m venv /opt/pve-exporter
/opt/pve-exporter/bin/pip install prometheus-pve-exporter
Créer l'utilisateur Proxmox dédié avec droits minimaux :
pveum user add pve-exporter@pve --comment "Prometheus PVE exporter"
pveum role add PVEExporter --privs "Datastore.Audit VM.Audit Pool.Audit Sys.Audit"
pveum acl modify / --user pve-exporter@pve --role PVEExporter
# Créer un token API (plus sûr qu'un mot de passe)
pveum user token add pve-exporter@pve prometheus --privsep 0
# Copier le token value affiché - il ne sera montré qu'une fois
Configuration pve-exporter :
# /etc/pve-exporter/pve.yml
default:
user: pve-exporter@pve
tokenname: prometheus
tokenvalue: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
verifyssl: false
cat > /etc/systemd/system/pve-exporter.service << 'EOF'
[Unit]
Description=PVE Prometheus Exporter
After=network.target
[Service]
ExecStart=/opt/pve-exporter/bin/pveexporter /etc/pve-exporter/pve.yml 9221 0.0.0.0
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
systemctl enable --now pve-exporter
Vérifier que les métriques Proxmox sont disponibles :
curl -s http://localhost:9221/pve?target=localhost | grep pveversion
# pveversioninfo{release="8.3",repoid="...",version="8.3"} 1
Déployer Grafana
Grafana dans le LXC 121, VLAN 30 :
pct create 121 local:vztmpl/debian-12-standard12.7-1amd64.tar.zst
--hostname grafana
--memory 512
--cores 1
--net0 name=eth0,bridge=vmbr0,tag=30,ip=192.168.30.121/24,gw=192.168.30.1
--storage rpool
--rootfs rpool:10
--unprivileged 1
--onboot 1
pct start 121
pct enter 121
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"
> /etc/apt/sources.list.d/grafana.list
apt update && apt install -y grafana
systemctl enable --now grafana-server
Grafana sur http://192.168.30.121:3000. Login : admin/admin, changer immédiatement.
Ajouter Prometheus comme datasource : Configuration > Data sources > Add > Prometheus > URL: http://192.168.30.120:9090.
Dashboards recommandés (import par ID depuis grafana.com) :
| Dashboard | ID | Usage |
|---|---|---|
| Node Exporter Full | 1860 | Métriques système de chaque machine |
| Proxmox VE | 10347 | Nœud Proxmox : VMs, LXC, stockage, réseau |
| ZFS | 7845 | Pools ZFS : santé, ARC, I/O |
| Pi-hole | 14559 | Requêtes DNS, domaines bloqués, clients |
AlertManager et alertes Telegram
AlertManager évalue les règles Prometheus et envoie des notifications. L'intégration Telegram via un bot est la plus simple à configurer.
Créer un bot Telegram : parler à @BotFather sur Telegram, /newbot, noter le token. Récupérer le chat ID : envoyer un message au bot, puis curl https://api.telegram.org/bot.
Installer AlertManager dans le LXC Prometheus (120) :
ALERTMANAGERVERSION="0.27.0"
cd /tmp
wget -q https://github.com/prometheus/alertmanager/releases/download/v${ALERTMANAGERVERSION}/alertmanager-${ALERTMANAGERVERSION}.linux-amd64.tar.gz
tar xzf alertmanager-${ALERTMANAGERVERSION}.linux-amd64.tar.gz
install -m 755 alertmanager-${ALERTMANAGERVERSION}.linux-amd64/alertmanager /usr/local/bin/
Configuration AlertManager :
# /etc/alertmanager/alertmanager.yml
global:
resolvetimeout: 5m
route:
groupby: ['alertname', 'job']
groupwait: 30s
groupinterval: 5m
repeatinterval: 4h
receiver: telegram
receivers:
- name: telegram
telegramconfigs:
- bottoken: 'TOKEN>'
chatid: ID>
message: |
{{ range .Alerts }}
{{ .Status | toUpper }} {{ .Labels.alertname }}
{{ .Annotations.summary }}
{{ if .Labels.instance }}Instance: {{ .Labels.instance }}{{ end }}
{{ end }}
parsemode: Markdown
Règles d'alerte critiques pour un homelab :
# /etc/prometheus/rules/homelab.yml
groups:
- name: homelab-critical
rules:
- alert: InstanceDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} injoignable depuis 2 minutes"
- alert: DiskSpaceCritical
expr: (nodefilesystemavailbytes{fstype!="tmpfs"} / nodefilesystemsizebytes) < 0.10
for: 5m
labels:
severity: critical
annotations:
summary: "Disque {{ $labels.mountpoint }} sur {{ $labels.instance }} à moins de 10%"
- alert: HighMemoryUsage
expr: (1 - (nodememoryMemAvailablebytes / nodememoryMemTotalbytes)) > 0.90
for: 10m
labels:
severity: warning
annotations:
summary: "{{ $labels.instance }} : utilisation RAM > 90%"
- alert: ZFSPoolDegraded
expr: nodezfspoolstate{state!="online"} == 1
for: 1m
labels:
severity: critical
annotations:
summary: "Pool ZFS {{ $labels.pool }} en état {{ $labels.state }}"
La règle DiskSpaceCritical aurait détecté le problème Nextcloud de l'introduction - 10% libre sur un volume de 50 Go, ça déclenche l'alerte à 5 Go restants. Largement le temps de réagir.
Ce qui a coincé
Le premier déploiement, pve-exporter retournait des métriques vides pour les VMs arrêtées. Dans Grafana, les panneaux "VMs running" affichaient 0 même quand des machines tournaient.
Le problème : pve-exporter était configuré avec un utilisateur pve-exporter@pve qui avait les droits sur / mais dans Proxmox, les droits sur / ne s'appliquent pas automatiquement aux pools ou ressources créées après l'attribution des droits.
Diagnostic avec promtool :
curl -s "http://192.168.1.10:9221/pve?target=localhost" | grep -c "pveguestinfo"
# 0 ← devrait être le nombre de VMs
Correction : reconfigurer les ACL avec la propagation activée :
pveum acl modify / --user pve-exporter@pve --role PVEExporter --propagate 1
Après redémarrage du service, toutes les VMs et LXC apparaissaient dans les métriques.
Deuxième incident : après une mise à jour du paquet prometheus-pve-exporter via pip, le format des métriques a changé. Les queries PromQL dans Grafana utilisaient pvecpuusageratio mais le nouveau format l'avait renommé pvecpuusagepercent. Tous les panneaux CPU dans le dashboard Proxmox affichaient "No data".
Correction : éditer chaque panel dans Grafana pour adapter le nom de métrique, ou revenir à la version antérieure du paquet. Depuis, je pin la version dans le service systemd :
/opt/pve-exporter/bin/pip install prometheus-pve-exporter==1.3.1
Et je documente la version dans /etc/pve-exporter/VERSION avant chaque mise à jour.
Série « Homelab Proxmox MS-01 » - Article 9/10