Tutoriel

Alertes disque plein et RAM sur VPS, sans stack de supervision

Sécurité & Monitoring13 min de lecture9 étapes

Un disque se remplit, la base de données s'arrête, et le client l'apprend avant vous. Le coût est une intervention en urgence et une confiance entamée. Une stack de supervision complète est un second serveur à entretenir, donc beaucoup d'agences y renoncent et ne surveillent rien. Ce guide pose six alertes minimales en shell sur chaque VPS : disque, inodes, mémoire, services, certificats, sauvegardes. Le contrôle est surveillé à son tour par un battement de cœur externe.

Sommaire· Le disque plein ne prévient personne1/14
  1. 01Le disque plein ne prévient personne
  2. 02Les six alertes minimales et le battement de cœur, sur chaque VPS
  3. 03Prérequis chiffrés : presque rien
  4. 04Disque et inodes : les seuils et ce qui les déplace
  5. 05Poser le dispositif en une heure
  6. 06Mémoire : OOM du noyau ou limite de cgroup
  7. 07OnFailure : ce qu'il couvre et ce qu'il ne couvre pas
  8. 08Certificats et sauvegardes : alerter sur l'absence de succès
  9. 09Scripts maison ou stack de supervision
  10. 10Surveillez le surveillant
  11. 11Dépannage : les erreurs qui reviennent
  12. 12Messages et symptômes avec leur remède
  13. 13La documentation officielle
  14. 14Des alertes simples, la même sur chaque VPS

Le disque plein ne prévient personne

Le scénario revient sans cesse. Un VPS client tourne depuis des mois, la base de données écrit ses journaux, les sauvegardes s'empilent, et un matin le service s'arrête. Aucune alerte n'est partie, le client l'apprend avant vous. Sur PostgreSQL, un cas rapporté sur la liste officielle du projet montre la ligne exacte : PANIC: could not write to file "pg_wal/xlogtemp.11399": No space left on device. Un PANIC n'est pas un simple avertissement : le serveur ne peut plus journaliser ses écritures, il s'arrête, et il ne redémarre proprement qu'une fois de la place libérée.

La difficulté n'est pas de détecter un disque plein, c'est de le détecter avant. Entre 80 % d'occupation et la panne, il reste souvent des heures ou des jours, et c'est exactement la fenêtre qu'une alerte bien réglée doit capter. Ce guide ne refait pas l'installation d'une stack de supervision : il pose le minimum utile sur chaque VPS, en shell, sans second serveur à entretenir.

Les six alertes minimales et le battement de cœur, sur chaque VPS

  • Disque — deux seuils, 80 % en avertissement et 90 % en critique, sur chaque point de montage utile.
  • Inodes — un disque peut refuser d'écrire alors qu'il reste de la place en octets, si les inodes sont épuisés.
  • Mémoire et OOM — détecter qu'un processus a été tué par le noyau, pas seulement que la RAM est haute.
  • Services systemd — être prévenu quand la base, le serveur web ou le proxy passe à l'état failed.
  • Certificats — alerter 21 jours avant l'échéance, quand le renouvellement automatique a échoué en silence.
  • Sauvegardes — alerter sur l'absence de succès récent, pas seulement sur une erreur explicite.
  • Le contrôle lui-même — un battement de cœur externe qui prévient quand les alertes cessent de partir.

Prérequis chiffrés : presque rien

Tout ce qui suit tient dans quelques dizaines de lignes de shell POSIX. Il faut un VPS Linux avec curl, cron ou les timers systemd, un accès root pour écrire dans /usr/local/bin et /etc, et environ 1 Mo de disque.

Deux éléments externes complètent le dispositif : un canal de réception (un bot Telegram, ou n'importe quel webhook accessible en HTTP) et un service de battement de cœur, qui reçoit un ping régulier et vous prévient quand il s'arrête. Pour ce second point, Healthchecks.io propose un plan gratuit limité à 20 jobs et 100 entrées de journal par job, ce qui couvre largement un parc de petite taille ; vérifiez ces limites à la source avant de vous y fier. Le mode push d'Uptime Kuma remplit le même rôle sur une machine à vous.

Disque et inodes : les seuils et ce qui les déplace

La commande utile est df -h --output=pcent,target : elle n'affiche que le pourcentage et le point de montage, ce qui se lit et se parse facilement. Pour les inodes, la même idée devient df --output=ipcent,target. Un dossier de sessions ou de petits fichiers de cache peut consommer tous les inodes d'un système de fichiers ext4 alors que df -h affiche encore 40 % d'occupation : l'écriture échoue pourtant avec le même No space left on device.

Il y a une seconde subtilité. Sur ext4, 5 % des blocs sont réservés par défaut aux processus privilégiés, d'après la page de manuel de tune2fs ; c'est ce qui permet aux démons système de continuer à écrire quand un utilisateur ordinaire a rempli le disque. Conséquence : un service qui tourne sous un compte non privilégié, comme la base de données, voit df afficher 100 % alors que le disque est occupé à environ 95 %. D'où les seuils retenus : 80 % pour avoir le temps d'agir, 90 % pour agir tout de suite. Attendre 100 % revient à alerter après la panne.

Poser le dispositif en une heure

  1. Créer le canal d'alerte

    Créez un bot Telegram avec BotFather, notez son jeton et l'identifiant de la conversation qui doit recevoir les messages. Toutes les requêtes de l'API Bot suivent la forme https://api.telegram.org/bot<token>/METHOD_NAME, et la méthode d'envoi est sendMessage.

  2. Écrire le fichier d'environnement

    sudo mkdir -p /var/lib/alerte-vps
    sudo install -m 600 /dev/null /etc/alerte-vps.env
    Puis ajoutez-y quatre lignes : TG_TOKEN=..., TG_CHAT=..., HC_URL=https://hc-ping.com/<uuid> (check toutes les cinq minutes) et HC_URL_JOUR=https://hc-ping.com/<autre-uuid> (check quotidien). Le mode 600 garde le jeton lisible par root seul.

  3. Écrire le script d'envoi avec anti-répétition

    Enregistrez ces lignes dans /usr/local/bin/alerte-envoi puis rendez le fichier exécutable avec sudo chmod 755. Le fichier de verrou par message évite d'être réveillé toutes les cinq minutes pour la même alerte : un message identique n'est renvoyé qu'après une heure.
    #!/bin/sh
    . /etc/alerte-vps.env
    f=/var/lib/alerte-vps/$(echo "$1" | md5sum | cut -c1-12)
    [ -n "$(find "$f" -mmin -60 2>/dev/null)" ] && exit 0
    touch "$f"
    curl -fsS -m 10 --retry 3 "https://api.telegram.org/bot${TG_TOKEN}/sendMessage" -d chat_id="${TG_CHAT}" --data-urlencode text="$(hostname) $1"

  4. Contrôler disque et inodes

    Dans /usr/local/bin/alerte-rapide (shebang #!/bin/sh), ajoutez les deux boucles suivantes. Le filtre grep -v écarte les systèmes de fichiers qui n'exposent pas d'inodes et affichent un tiret.
    df --output=pcent,target -x tmpfs -x devtmpfs | tail -n +2 | while read p m; do n=${p%\%}; if [ "$n" -ge 90 ]; then alerte-envoi "CRIT disk $m"; elif [ "$n" -ge 80 ]; then alerte-envoi "WARN disk $m"; fi; done
    df --output=ipcent,target -x tmpfs -x devtmpfs | tail -n +2 | grep -v '^ *-' | while read p m; do [ "${p%\%}" -ge 90 ] && alerte-envoi "INODES $m"; done

  5. Détecter les processus tués par l'OOM killer

    Le compteur oom_kill de /proc/vmstat ne fait que croître depuis le démarrage. On le compare à la valeur précédente, conservée dans un fichier ; après un redémarrage le compteur repart de zéro, la comparaison est fausse une fois, puis se rétablit.
    n=$(awk '/^oom_kill/ {print $2}' /proc/vmstat)
    old=$(cat /var/lib/alerte-vps/oom 2>/dev/null || echo 0)
    [ "$n" -gt "$old" ] && alerte-envoi "OOM kill"
    echo "$n" > /var/lib/alerte-vps/oom

  6. Ajouter le battement de cœur et planifier

    Terminez alerte-rapide par le ping. Il n'est atteint que si le script a tourné jusqu'au bout ; si cron s'arrête, si le disque est en lecture seule ou si le script plante, le ping cesse et le service externe vous prévient. Ajoutez ensuite les lignes de cron dans /etc/cron.d/alerte-vps.
    . /etc/alerte-vps.env; curl -fsS -m 10 --retry 5 -o /dev/null "$HC_URL"
    PATH=/usr/local/bin:/usr/bin:/bin
    */5 * * * * root /usr/local/bin/alerte-rapide
    30 7 * * * root /usr/local/bin/alerte-quotidien

  7. Contrôler certificats et sauvegardes une fois par jour

    Dans /usr/local/bin/alerte-quotidien, ajoutez ces lignes. L'option -checkend d'openssl x509 échoue si le certificat expire dans le nombre de secondes donné ; 1814400 secondes valent 21 jours. Le test de sauvegarde alerte quand aucun fichier .gz non vide n'est plus récent que 1560 minutes, soit 26 heures. Le script se termine par son propre ping, vers le second check : sans lui, un contrôle quotidien tombé en silence passerait inaperçu.
    echo | openssl s_client -servername votre-domaine.com -connect votre-domaine.com:443 2>/dev/null | openssl x509 -noout -checkend 1814400 || alerte-envoi "CERT votre-domaine.com"
    find /var/backups/app -name '*.gz' -mmin -1560 -size +1k | grep -q . || alerte-envoi "BACKUP absent"
    . /etc/alerte-vps.env; curl -fsS -m 10 --retry 5 -o /dev/null "$HC_URL_JOUR"

  8. Brancher les services critiques sur OnFailure

    Créez /etc/systemd/system/[email protected] avec le contenu suivant, puis sudo systemctl daemon-reload.
    [Unit]
    Description=Alerte echec de %i
    [Service]
    Type=oneshot
    ExecStart=/usr/local/bin/alerte-envoi "FAILED %i"
    Pour chaque service à surveiller, ouvrez un drop-in avec sudo systemctl edit mariadb.service et ajoutez ces deux lignes.
    [Unit]
    OnFailure=notify-failure@%n.service

  9. Forcer une alerte pour tester, puis nettoyer

    Une alerte jamais déclenchée n'est pas une alerte. Vérifiez d'abord l'espace libre, créez un fichier assez gros pour franchir le seuil, lancez le script à la main, puis supprimez le fichier. Si le message n'arrive pas, le défaut est dans le canal, et il vaut mieux le découvrir maintenant.
    df -h --output=pcent,target /var/tmp
    sudo fallocate -l 2G /var/tmp/test-alerte.img
    sudo /usr/local/bin/alerte-rapide
    sudo rm /var/tmp/test-alerte.img

Mémoire : OOM du noyau ou limite de cgroup

Deux mécanismes tuent un processus pour manque de mémoire, et ils ne se lisent pas au même endroit. Le premier est l'OOM killer du noyau, quand la machine entière manque de RAM : le journal du noyau contient alors un message du type Out of memory: Killed process, que journalctl -k permet de retrouver. Le second est la limite d'un cgroup. Selon la documentation de systemd, quand l'usage d'une unité ne peut pas être contenu sous MemoryMax=, l'OOM killer est invoqué à l'intérieur de l'unité : le reste de la machine peut avoir de la mémoire libre.

Le compteur oom_kill de /proc/vmstat couvre le premier cas à l'échelle de la machine. Pour une unité précise, le fichier memory.events de son cgroup expose un compteur oom_kill propre, défini par la documentation du noyau comme le nombre de processus du cgroup tués par n'importe quel type d'OOM killer. Sur un VPS qui héberge une application gourmande, comme celle décrite dans le guide n8n et OOM en production, c'est ce second compteur qui explique les arrêts que free -h ne montre jamais.

OnFailure : ce qu'il couvre et ce qu'il ne couvre pas

Selon la documentation de systemd, OnFailure= liste les unités activées quand l'unité entre dans l'état failed. Le gabarit [email protected] reçoit le nom de l'unité fautive grâce au spécificateur %n, et le message d'alerte peut y joindre la sortie de systemctl status ou de journalctl -u pour le contexte.

La limite est structurelle : un service qui tourne mais ne répond plus n'est jamais passé par l'état failed, donc OnFailure= ne dit rien. Un service relancé par Restart= n'y arrive qu'une fois la limite de démarrage atteinte. Pour ces cas, ajoutez une sonde applicative simple, par exemple un curl sur l'adresse de santé de l'application, dans le script rapide. La syntaxe des timers et de cron est traitée dans le guide cron et timers systemd, et il n'y a pas lieu de la répéter ici.

Certificats et sauvegardes : alerter sur l'absence de succès

Un renouvellement automatique de certificat peut échouer en silence pendant des semaines : un enregistrement DNS modifié, un port bloqué, un plugin cassé. Le test openssl interroge ce que le visiteur reçoit réellement, ce qui vaut mieux que de lire un fichier sur le disque. Sur un serveur géré par Certbot, certbot certificates liste les certificats et leur échéance, et certbot renew --dry-run vérifie que le renouvellement futur aboutira.

Même logique pour les sauvegardes. Une alerte déclenchée par l'échec d'un script de sauvegarde ne voit pas le cas où le script ne s'est jamais lancé. L'alerte correcte se pose sur l'absence : aucun fichier récent, ou un fichier de taille nulle. C'est ce que fait la ligne find -mmin du script quotidien, et c'est pourquoi elle reste muette quand tout va bien et bavarde dès que la chaîne de sauvegarde s'arrête, quelle qu'en soit la raison.

Scripts maison ou stack de supervision

Faites défiler le tableau

CritèreScripts shell et OnFailureBeszel ou Uptime Kuma
Mise en placeUne heure, quelques fichiers dans `/usr/local/bin`Un hub à héberger, des agents à installer sur chaque VPS
Parc visé1 à 5 VPS, jusqu'à 10 si les seuils sont identiquesAu-delà de 5 à 10 VPS, ou dès qu'il faut comparer
Historique et courbesAucun, seulement l'instant de l'alerteGraphiques, tendances, comparaison entre machines
EntretienRien à mettre à jour hors du shellUn second serveur et ses mises à jour à tenir
Services applicatifsSonde `curl` à écrire soi-mêmeSondes HTTP, TCP et page de statut prêtes à l'emploi
Panne du moniteurDétectée par le battement de cœur externeÀ surveiller séparément, le hub est lui-même une machine
Quand le choisirAlertes minimales, parc réduit, zéro serveur en plusHistorique voulu, parc en croissance, équipe partagée

Surveillez le surveillant

Le piège de ces scripts est de devenir une fausse assurance : ils se taisent parce que tout va bien, ou parce qu'ils sont cassés, et le silence ressemble dans les deux cas. Le ping de battement de cœur règle le problème. Réglez la période attendue du check un peu au-dessus de l'intervalle de cron, avec une marge de tolérance. Gardez aussi /etc/alerte-vps.env en mode 600 et ne versionnez jamais le jeton.

Dépannage : les erreurs qui reviennent

Les alertes elles-mêmes tombent en panne de façon prévisible. Chaque cas se vérifie à la main avant de chercher plus loin.

Messages et symptômes avec leur remède

  • PANIC: could not write to file "pg_wal/...": No space left on device — le volume qui porte les journaux de PostgreSQL est plein. Libérez d'abord de la place hors de PostgreSQL (journaux tournants, anciennes sauvegardes), ne supprimez jamais les fichiers de pg_wal à la main, puis redémarrez le service.
  • No space left on device alors que df -h annonce de la place — les inodes sont épuisés. Lancez df --output=ipcent,target, repérez le dossier qui contient des millions de petits fichiers (sessions, cache) et purgez-le.
  • Disque plein mais du ne retrouve pas l'espace — des fichiers supprimés restent ouverts par un processus. sudo lsof +L1 les liste ; redémarrer le processus concerné libère l'espace.
  • oom_kill augmente, rien dans journalctl -k — le noyau a roulé ses journaux ou la mort vient d'une limite MemoryMax=. Lisez memory.events dans le répertoire du cgroup de l'unité et journalctl -u pour l'unité.
  • Une unité tourne mais ne répond plus, aucune alerte — c'est la limite de OnFailure=. Ajoutez une sonde curl sur l'adresse de santé et alertez sur le code de retour.
  • Aucun message Telegram, aucune erreur visible — cron envoie la sortie du script par courrier local, que personne ne lit. Lancez alerte-envoi test à la main avec sudo et lisez la réponse de curl.
  • Le certificat approche de l'échéance alors que Certbot est installé — lancez certbot renew --dry-run et lisez l'erreur de validation, puis corrigez le DNS ou le port concerné.

La documentation officielle

Chaque comportement décrit ici vient d'une source primaire. Pour OnFailure=, la page de manuel de systemd.unit ; pour MemoryMax=, systemd.resource-control ; pour les compteurs oom et oom_kill, la documentation des cgroups v2 du noyau ; pour les 5 % réservés, la page de manuel de tune2fs. Côté envoi, l'API Bot de Telegram décrit la forme des requêtes, et la documentation de l'API Healthchecks les adresses de ping, avec la page des tarifs pour les limites du plan gratuit. Pour le renouvellement, la documentation de Certbot. Le message PostgreSQL cité vient d'un fil de la liste officielle du projet.

Des alertes simples, la même sur chaque VPS

Six alertes et un battement de cœur ne remplacent pas une stack de supervision, ils couvrent ce qui fait réellement tomber un serveur : disque, inodes, mémoire, services, certificats, sauvegardes. Le gain principal est l'homogénéité : mêmes seuils et mêmes messages sur chaque machine. Quand le parc grandit ou que l'historique devient nécessaire, la bascule vers une stack se prépare dans le guide Beszel et dans le guide des alertes proactives Beszel et Uptime Kuma, qui traitent l'installation de bout en bout.

Un parc de VPS clients, des seuils homogènes

Sur ServOrbit.com, domaines, hébergements et serveurs d'un parc client se regroupent au même endroit, avec le même espace de gestion. L'option administration VPS existe pour les clients qui ne veulent pas administrer leur serveur.

Besoin d'aide ?

Parcourez notre centre d'aide et notre FAQ, ou contactez notre équipe — rappel, WhatsApp ou e-mail. Support en français, anglais et arabe.

Écrire sur WhatsApps'ouvre dans un nouvel onglet