Superviser un serveur Ubuntu sans prolifération d'agents : ce qu'il faut vraiment mesurer
Quatre mesures qui rendent 90 % des incidents visibles à l'avance, avec uniquement ce qui est livré avec Ubuntu 24.04 ou Debian 12 : sysstat, journalctl, df et un script cron de trente lignes qui pousse vers votre téléphone. Et pourquoi « CPU au-dessus de 90 % » est une mauvaise alerte.
Sommaire
- Étape 1 : savoir ce qui se passe maintenant (les cinq commandes)
- Étape 2 : activer l'historique (sysstat)
- Étape 3 : les quatre mesures qui comptent
- Étape 4 : un script cron qui parle à votre téléphone
- Étape 5 : prédire la croissance du disque au lieu de la découvrir
- Pièges
- Ce qu'il vous manque encore
- Comment monsys fait
- FAQ
La plupart des serveurs ne tombent pas à cause de quelque chose d'exotique. Ils tombent parce qu'un disque s'est rempli, qu'un processus a lentement mangé toute la mémoire, qu'un service n'est pas revenu après une mise à jour, ou qu'un journal a saturé la partition racine. Les quatre sont visibles des jours à l'avance — si quelqu'un regarde. Ce guide met en place ce regard avec ce qui est déjà sur la machine : pas d'agent, pas de SaaS, pas de Grafana. Ensuite, vous lirez ce qui vous manque encore.
Étape 1 : savoir ce qui se passe maintenant (les cinq commandes)
Avant d'automatiser quoi que ce soit, il faut connaître la version manuelle. Voici les cinq commandes que vous lancez en premier à chaque « le serveur est lent ».
# 1. Qui mange le CPU et la mémoire ?
top -bn1 | head -20
# 2. Est-ce le CPU, les I/O ou le swap ? (sysstat)
sudo apt install -y sysstat
vmstat 1 5 # colonnes r (file d'attente), si/so (swap in/out), wa (attente I/O)
iostat -xz 1 3 # %util par disque, await en ms
# 3. Disque : octets ET inodes
df -h --output=target,pcent,avail | sort -k2 -rn | head
df -i | awk 'NR==1 || $5+0 > 80'
# 4. Qu'est-ce qui a échoué ?
systemctl --failed
journalctl -p err -b --no-pager | tail -30
# 5. L'OOM killer a-t-il tué quelque chose ?
journalctl -k -b | grep -iE 'out of memory|oom-kill' | tail
Deux erreurs de lecture classiques chez les débutants :
free -maffiche presque toujours « free » bas. Regardez la colonne available. Linux utilise la mémoire libre comme cache de pages et la rend quand c'est nécessaire.load averagen'est pas un pourcentage. Une charge de 4 sur une machine à 8 cœurs est calme ; sur une machine à 2 cœurs, cela signifie que des processus attendent en permanence. Comparez toujours avecnproc.
Étape 2 : activer l'historique (sysstat)
Sans historique, vous ne pourrez jamais dire « c'est depuis mardi ». sysstat prend un instantané toutes les 10 minutes et garde 28 jours par défaut.
sudo apt install -y sysstat
# Ubuntu 24.04 et Debian 12 utilisent des timers systemd :
sudo systemctl enable --now sysstat-collect.timer sysstat-summary.timer
# Sur Debian/Ubuntu plus anciens : mettre ENABLED="true" dans /etc/default/sysstat
# À partir de demain, vous pouvez regarder en arrière :
sar -u # CPU aujourd'hui, par 10 min
sar -r # mémoire
sar -d -p # I/O disque par périphérique
sar -n DEV # réseau par interface
sar -u -f /var/log/sysstat/sa12 # le 12 de ce mois
Vous voulez 90 jours ? Mettez HISTORY=90 dans /etc/sysstat/sysstat. Cela coûte quelques Mo par mois.
Étape 3 : les quatre mesures qui comptent
Vous pourriez mesurer cent choses. Voici les quatre dont l'absence vous coûte un incident :
| Mesure | Pourquoi | Seuil qui fonctionne |
|---|---|---|
| Remplissage disque et sa direction | Disque plein = base de données arrêtée, logs arrêtés, mises à jour en échec | > 85 % ou « plein dans 7 jours » selon la croissance |
| Unités en échec + reboot-required | Un service qui n'est pas revenu après une mise à jour, c'est le client qui le remarque | systemctl --failed ≠ 0, ou /var/run/reboot-required existe depuis > 3 jours |
| OOM kills | La fuite mémoire d'aujourd'hui est la panne de la semaine prochaine | ≥ 1 OOM kill en 24 h |
| Heartbeat | Le serveur lui-même a disparu, donc il ne signale rien | Aucun ping en 5 min |
Notez ce qui n'y est pas : « CPU > 90 % ». Une sauvegarde, un apt upgrade, un logrotate nocturne avec compression, un cron qui construit un rapport — tout ça, 100 % de CPU, tout ça normal. Cette alerte vous apprend à l'ignorer en une semaine, et alors vous ratez la vraie. Alertez sur des symptômes (files d'attente, attente I/O au-dessus de 30 % pendant 10 minutes, temps de réponse) ou sur l'écart au comportement normal pour cette heure, pas sur un chiffre absolu.
Étape 4 : un script cron qui parle à votre téléphone
Trente lignes, aucune dépendance hormis curl. Le push part vers ntfy — auto-hébergeable, gratuit, hébergeable en UE. Remplacez NTFY par votre propre topic.
sudo tee /usr/local/sbin/healthcheck.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
# Tourne toutes les 10 min via cron. Ne signale que ce qui dévie.
NTFY="https://ntfy.example.be/servers"
HOST=$(hostname -s)
ALERTS=()
# Disque > 85 % (octets ou inodes), tmpfs exclus
while read -r target pct; do
ALERTS+=("disk $target ${pct}")
done < <(df -x tmpfs -x devtmpfs --output=target,pcent | awk 'NR>1 && $2+0>85')
while read -r target pct; do
ALERTS+=("inodes $target ${pct}")
done < <(df -x tmpfs -x devtmpfs --output=target,ipcent | awk 'NR>1 && $2+0>85')
# Unités en échec
FAILED=$(systemctl --failed --no-legend | awk '{print $1}' | tr '\n' ' ')
[ -n "$FAILED" ] && ALERTS+=("failed: $FAILED")
# Reboot requis depuis > 3 jours
if [ -f /var/run/reboot-required ] && [ "$(find /var/run/reboot-required -mtime +3)" ]; then
ALERTS+=("reboot-required > 3d ($(tr '\n' ' ' </var/run/reboot-required.pkgs))")
fi
# OOM kills des dernières 24 h
OOM=$(journalctl -k --since "24 hours ago" --no-pager | grep -ci 'out of memory')
[ "$OOM" -gt 0 ] && ALERTS+=("oom-kills: $OOM")
# Charge > 2x cœurs, moyenne 15 min (donc pas de pic court)
CORES=$(nproc); LOAD15=$(awk '{print $3}' /proc/loadavg)
awk -v l="$LOAD15" -v c="$CORES" 'BEGIN{exit !(l > 2*c)}' && ALERTS+=("load15 $LOAD15 on $CORES cores")
if [ ${#ALERTS[@]} -gt 0 ]; then
printf '%s\n' "${ALERTS[@]}" | curl -s -H "Title: $HOST" -H "Priority: high" --data-binary @- "$NTFY" >/dev/null
fi
EOF
sudo chmod 0755 /usr/local/sbin/healthcheck.sh
echo '*/10 * * * * root /usr/local/sbin/healthcheck.sh' | sudo tee /etc/cron.d/healthcheck
Testez avec un échec artificiel : sudo systemctl mask cron && sudo systemctl restart cron produit une unité en échec. N'oubliez pas de unmask.
Heartbeat : le serveur qui ne dit plus rien
Le script ci-dessus ne peut pas signaler que le serveur lui-même a disparu. Pour cela, il faut une deuxième machine (ou votre portable) qui s'attend à recevoir quelque chose. Forme la plus simple : le script fait un curl vers un topic ntfy heartbeat-$HOST toutes les 10 minutes, et un cron sur un autre hôte vérifie si le dernier message a plus de 15 minutes via curl "https://ntfy.example.be/heartbeat-$HOST/json?poll=1&since=15m". C'est rustique, et ça marche.
Étape 5 : prédire la croissance du disque au lieu de la découvrir
« 85 % » sur un disque qui croît de 1 % par mois n'est pas un problème. « 60 % » sur un disque qui croît de 5 % par jour est une panne dans huit jours. Avec sar -F (Ubuntu 24.04+) ou votre propre petit journal, vous calculez la pente :
# Journaliser le remplissage chaque jour
echo "0 6 * * * root df -B1 --output=target,used / /var | tail -n +2 | sed \"s/^/\$(date +\\%F) /\" >> /var/log/diskgrowth.log" | sudo tee /etc/cron.d/diskgrowth
# Après une semaine : octets par jour et jours avant saturation
awk -v total="$(df -B1 --output=size / | tail -1)" '
$2=="/" {n++; x[n]=n; y[n]=$3}
END {
for(i=1;i<=n;i++){sx+=x[i];sy+=y[i];sxy+=x[i]*y[i];sxx+=x[i]*x[i]}
slope=(n*sxy-sx*sy)/(n*sxx-sx*sx)
if (slope<=0) {print "en baisse ou stable"; exit}
printf "croissance %.1f Mo/jour, plein dans %.0f jours\n", slope/1e6, (total-y[n])/slope
}' /var/log/diskgrowth.log
C'est une régression linéaire en awk. Pas élégant, mais suffisant pour planifier un achat ou un nettoyage deux semaines à l'avance.
Pièges
- journald dévore votre disque.
journalctl --disk-usagesurprend. MettezSystemMaxUse=500Mdans/etc/systemd/journald.confetsystemctl restart systemd-journald. dfne voit pas les fichiers supprimés mais ouverts. Un fichier de log de 20 Go supprimé alors que nginx le tient encore ouvert continue d'occuper l'espace.sudo lsof +L1les montre ; un reload du processus libère l'espace.- Snapshots et
/boot. Les snapshots LVM et les anciens noyaux remplissent/bootjusqu'à ce qu'unapt upgradeéchoue. Incluez/bootdans la vérification disque et lancezapt autoremove --purgerégulièrement. - Fuseau horaire dans cron.
crontourne dans le fuseau du système ; vos messages ntfy etsaraussi. Si le serveur est en UTC et que vous regardez depuis Bruxelles, « à 3 heures » est faux.timedatectlvous le dit. - Alertes sans propriétaire. Un script qui pousse vers un topic auquel plus personne n'est abonné n'est pas de la supervision. Dans l'agenda : une alerte de test par trimestre.
Ce qu'il vous manque encore
Cela fonctionne très bien pour un à cinq serveurs. Ensuite, vous butez sur les mêmes quatre murs :
- Pas d'historique entre hôtes.
sarregarde par machine. « Lequel de mes vingt serveurs croît le plus vite ? » est une boucle for sur ssh, à chaque fois. - Pas de déduplication. Un disque à 86 % produit un push toutes les 10 minutes jusqu'à ce que quelqu'un agisse. Après un jour, tout le monde ignore le topic.
- Pas de baseline. Le script ne sait pas que cet hôte a toujours une charge de 6 le mardi soir à cause de la sauvegarde. Vous, oui — votre remplaçant, non.
- Pas de preuve. Un auditeur NIS2 ou ISO 27001 demande « comment savez-vous que votre supervision fonctionne ? » et un fichier cron est une réponse faible.
Comment monsys fait
L'agent monsys (un binaire Rust statique, sans dépendances) mesure les mêmes choses — CPU, mémoire, disque par point de montage, réseau par interface, unités en échec, OOM kills, reboot-required — toutes les 15 secondes, et envoie des signaux agrégés au hub. Le hub construit par hôte une baseline par heure de la journée pour que vous puissiez alerter sur l'écart plutôt que sur un chiffre absolu, déduplique les alertes en une ligne ouverte par cause, et conserve 13 mois d'historique pour les questions de capacité. Le silence de heartbeat est une détection séparée, qui distingue « brièvement absent » de « silencieux depuis des jours ».
Les cinq premiers serveurs sont gratuits, pour toujours. L'installation tient en une ligne : curl -fsSL https://get.monsys.ai/install.sh | sudo bash.
FAQ
90 % d'utilisation CPU, est-ce un problème ?
Pas en soi. Un serveur qui utilise son CPU fait son travail. Cela devient un problème quand une file d'attente se forme en même temps (colonne r de vmstat structurellement supérieure au nombre de cœurs) ou quand le temps de réponse de votre application augmente. Alertez sur ces symptômes, pas sur le pourcentage.
Ai-je besoin de Prometheus ou Grafana pour quelques serveurs ?
Non. Pour moins de cinq serveurs, sysstat plus un script cron avec notifications push vous donne 90 % de la valeur pour 5 % de la maintenance. Prometheus devient intéressant quand vous voulez des tableaux de bord sur plusieurs hôtes ou que vous commencez à collecter des métriques applicatives.
Cela fonctionne-t-il aussi sur Debian 12 ?
Oui, toutes les commandes de cet article ont été testées sur Debian 12 et Ubuntu 24.04. La seule différence est le nom de certaines unités ; sysstat-collect.timer existe sur les deux.
Rédigé par l'équipe monsys — des sysadmins qui font cela tous les jours.
Fait à la main ? Laissez monsys s'en charger en continu.
Tout ce que contient ce guide tourne dans monsys comme contrôle permanent, avec historique, alertes et preuves d'audit. 5 serveurs gratuits, hébergés en Belgique, installés en 60 secondes.