Loki + Promtail : centraliser les logs de tout ton homelab dans Grafana
Pendant longtemps, déboguer un problème sur le homelab ressemblait à une chasse au trésor sans…
Le monitoring sans alertes, c’est un dashboard que tu regardes uniquement quand tu penses à le regarder – c’est-à-dire jamais quand ça compte vraiment. J’avais Grafana + Prometheus en place depuis l’article 9 de cette série, avec des dashboards propres sur hubble.arewel.com. Mais j’ai découvert qu’un disque était plein sur une VM de test après que le service s’était silencieusement arrêté depuis 48 heures. C’est le genre d’incident qui convainc d’activer les alertes dans la journée.
Ce guide suppose que tu as déjà Grafana 11.x et Prometheus opérationnels. Si ce n’est pas le cas, commence par l’article 9 de la série.
Avant Grafana 9, les alertes étaient définies directement dans les panels – ce que Grafana appelle désormais « Legacy Alerting ». Depuis la version 9, le système unifié (Grafana Alerting) est le seul disponible pour les nouvelles installations. Grafana 11.x n’offre plus que ce système. La distinction est importante si tu tombes sur des tutoriels anciens qui décrivent des menus différents.
Le flux est le suivant : les règles d’alerte sont évaluées périodiquement par le moteur Grafana selon une requête PromQL (ou Loki, ou autre datasource). Quand une règle passe en état Firing, une notification est envoyée via un Contact Point. Les politiques de routage (Notification Policies) déterminent quel Contact Point reçoit quelle alerte selon des labels.
En pratique pour un homelab mono-opérateur, une politique de routage par défaut qui envoie tout vers un seul Contact Point est largement suffisante. Tu affines plus tard.
Telegram est le canal que j’utilise en priorité – les notifications arrivent sur le téléphone avec une mention du nom de l’alerte et les labels associés, même sans connexion permanente à l’app.
Créer un bot via @BotFather : commande /newbot, choisir un nom, récupérer le token API (format 123456789:AAF...). Ce token ne doit pas être versionné ni partagé.
Ensuite, créer un groupe Telegram ou utiliser une conversation directe avec le bot. Ajouter le bot au groupe, puis récupérer le chat_id. Le moyen le plus simple : envoyer un message dans le groupe, puis appeler :
https://api.telegram.org/bot/getUpdates
Le chat_id est dans le champ message.chat.id de la réponse JSON. Pour les groupes, il est négatif (-100...).
Dans Grafana, Alerting > Contact Points > Add contact point :
telegram-homelabTelegramCliquer « Test » – tu dois recevoir un message test dans Telegram immédiatement. Si ce n’est pas le cas, vérifier que le bot a bien été ajouté au groupe et que le chat_id est correct.
Discord est mon canal secondaire – utile pour avoir un historique des alertes dans un channel dédié, que je consulte avec d’autres membres du réseau homelab.
Dans les paramètres de ton serveur Discord : Paramètres du serveur > Intégrations > Webhooks > Nouveau Webhook. Choisir le channel cible, copier l’URL du webhook (format https://discord.com/api/webhooks/...).
Dans Grafana, nouveau Contact Point :
discord-homelabDiscordTu peux configurer un avatar et un nom d’affichage pour le webhook Discord directement dans les paramètres Discord – ça rend l’historique des alertes plus lisible dans le channel.
Gotify est un serveur de notifications push open source avec des apps Android et iOS. L’intérêt par rapport à Telegram : aucune dépendance à un service tiers, le serveur tourne chez toi.
J’ai un LXC dédié (CT 112) sous Debian 12 minimal, avec 1 vCPU et 64 MB de RAM allouée – Gotify consomme réellement autour de 30 MB en fonctionnement. Le binaire Gotify est disponible sur le dépôt GitHub officiel.
Installation dans le LXC 112 :
mkdir -p /opt/gotify/data
# Télécharger le binaire (adapter la version)
wget https://github.com/gotify/server/releases/download/v2.4.0/gotify-linux-amd64.zip
unzip gotify-linux-amd64.zip -d /opt/gotify/
# Créer un service systemd
cat > /etc/systemd/system/gotify.service << 'EOF'
[Unit]
Description=Gotify Server
After=network.target
[Service]
ExecStart=/opt/gotify/gotify-linux-amd64
WorkingDirectory=/opt/gotify/data
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
systemctl enable gotify && systemctl start gotify
Gotify écoute sur le port 80 par défaut. L'interface web est accessible sur http://. Créer un compte admin, puis créer une application dans l'interface pour obtenir un token d'application.
Dans Grafana, Contact Point Gotify :
Webhookhttp:///message?token= POSTContent-Type: application/jsonGotify ne dispose pas d'une intégration native dans Grafana, mais un webhook POST avec le bon format fonctionne. Le template de message :
{
"title": "{{ .GroupLabels.alertname }}",
"message": "{{ range .Alerts }}{{ .Annotations.summary }}n{{ end }}",
"priority": 5
}
Voici les règles que j'ai configurées, avec les expressions PromQL complètes. Toutes utilisent une source de données Prometheus.
CPU élevé sur un nœud
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle",job="homelab"}[5m])) * 100) > 85
Seuil : 85%. Condition for: 5m - l'alerte ne se déclenche que si la condition persiste 5 minutes d'affilée. Les pics courts (compilation, sauvegarde) ne génèrent pas de notification.
RAM élevée
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 90
Seuil : 90%. Condition for: 5m.
Espace disque faible
(1 - (node_filesystem_avail_bytes{fstype!~"tmpfs|fuse.lxcfs"} / node_filesystem_size_bytes{fstype!~"tmpfs|fuse.lxcfs"})) * 100 > 80
Seuil : 80%. On exclut les filesystems tmpfs et fuse.lxcfs (LXC) pour éviter les faux positifs. Condition for: 10m - le disque ne se remplit pas soudainement, 10 minutes de grâce est raisonnable.
Service down (node_exporter)
up{job="homelab"} == 0
Condition for: 2m - voir la section suivante sur les faux positifs.
Nœud Proxmox offline
pve_up{job="proxmox"} == 0
Nécessite que pve_exporter soit configuré dans Prometheus pour le job proxmox. Condition for: 2m.
Pour chaque règle, renseigner les annotations summary et description - ce sont elles qui apparaissent dans la notification Telegram :
summary: "CPU élevé sur {{ $labels.instance }}"
description: "CPU à {{ $value | printf "%.1f" }}% depuis 5 minutes sur {{ $labels.instance }}"
La règle up == 0 est la première que j'ai configurée et la première à m'avoir posé des problèmes. Chaque fois que je redémarrais un service ou un LXC pour une mise à jour, l'alerte se déclenchait - même si le service était de nouveau opérationnel 30 secondes plus tard.
La solution est la condition for: dans la définition de la règle d'alerte. En Grafana Alerting, for: 2m signifie que la condition doit être vraie en continu pendant 2 minutes avant que l'alerte passe en état Firing. Un redémarrage standard d'un LXC ou d'un service Docker prend moins de 60 secondes : la condition revient à zéro avant d'atteindre les 2 minutes, et aucune notification n'est envoyée.
La valeur for: ne s'applique qu'au passage de Normal à Firing. Une fois en Firing, l'alerte reste dans cet état jusqu'à ce que la condition soit fausse, quelle que soit la durée. Ne pas confondre avec un délai de re-notification.
Après avoir ajouté for: 2m à toutes mes règles de type up == 0, les faux positifs ont disparu.
Certains événements sont prévisibles et ne doivent pas générer de notifications : le redémarrage hebdomadaire du service Proxmox Backup Server, les maintenances planifiées, les tests de failover cluster.
Alerting > Silences > Add Silence :
alertname=~".*" pour tout silencer, ou instance="heighliner" pour silencer uniquement les alertes d'un nœudCrée les silences à l'avance, pas en urgence pendant la maintenance. Tu t'évites le stress de chercher le menu Grafana avec les mains pleines de câbles.
Si heighliner tombe, tous ses services tombent avec lui. Sans groupement, tu reçois une notification par alerte : CPU, RAM, disque, service Nextcloud, service Vaultwarden, service Pi-hole - soit 10 à 15 messages Telegram en rafale. C'est ce qu'on appelle une alerte storm, et c'est aussi pénible que d'ignorer les alertes.
Dans Notification Policies, la politique par défaut a des paramètres de groupement. Configurer :
alertname, instance (regroupe toutes les alertes du même nœud)30s (attend 30 secondes avant d'envoyer pour agréger les alertes simultanées)5m (délai entre deux notifications pour le même groupe)4h (renvoie une notification si l'alerte est toujours active après 4 heures)Avec ces paramètres, la perte complète d'un nœud génère une seule notification groupée après 30 secondes - pas 15 messages.
Depuis l'activation des alertes, j'ai reçu 3 notifications Telegram :
La première : disque plein à 92% sur la VM de test (VM-117). Un journal applicatif qui n'était pas rotatif. Résolu en ajoutant logrotate et en vidant manuellement /var/log/app/. Sans l'alerte, ce service serait resté silencieusement mort.
La deuxième : le service Gitea dans un LXC (CT 109) en crash loop. Le for: 2m a correctement attendu que le service ne redémarre pas seul. Cause : mise à jour de Gitea qui avait modifié le format de la base SQLite. Résolu en suivant le guide de migration Gitea.
La troisième : faux positif pendant la mise à jour de node_exporter sur heighliner. Le service a été down pendant environ 90 secondes pendant la mise à jour - juste au-delà du seuil de 2 minutes configuré. J'aurais dû créer un silence avant la mise à jour. Leçon retenue.
Le ratio signal/bruit est bon : 2 vraies alertes sur 3 en 3 semaines, ce qui est mieux que ce que j'avais avant (zéro alerte, donc zéro signal).
slug: grafana-alerting-telegram-discord-gotify-homelab
meta: Configurer Grafana Alerting 11.x avec Telegram, Discord et Gotify auto-hébergé. Règles PromQL essentielles, silences, groupement et gestion des faux positifs.
tags: grafana, alerting, telegram, prometheus, gotify, homelab
Cet article est vivant - corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.