Général 6 min de lecture · 1 101 mots

Monitorer son homelab Proxmox avec Grafana, Prometheus et node_exporter

Monitorer son homelab Proxmox avec Grafana, Prometheus et node_exporter
Général · 2026.06.09

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/getUpdates.

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

Une remarque, un retour ?

Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.

Laisser un commentaire