Ubuntu-server monitoren zonder agent-wildgroei: wat je écht moet meten
Vier metingen die 90 % van de incidenten vooraf zichtbaar maken, met alleen wat er standaard op een Ubuntu 24.04- of Debian 12-server staat: sysstat, journalctl, df en een cron-script van dertig regels dat naar je telefoon pusht. Plus waarom "CPU boven 90 %" een slechte alert is.
Inhoud
De meeste servers gaan niet plat door iets exotisch. Ze gaan plat door een volle schijf, een proces dat langzaam al het geheugen opeet, een service die na een update niet meer opkwam, of een journal dat de root-partitie volschrijft. Alle vier zijn dagen van tevoren zichtbaar, als iemand kijkt. Deze how-to zet dat kijken op met wat er al op de machine staat: geen agent, geen SaaS, geen Grafana. Daarna lees je wat je dan nog mist.
Stap 1: weet wat er nú gebeurt (de vijf commando's)
Voor je iets automatiseert, moet je de handmatige versie kennen. Dit zijn de vijf commando's die je bij elke "de server is traag"-melding als eerste draait.
# 1. Wie eet de CPU en het geheugen?
top -bn1 | head -20
# 2. Is het CPU, I/O of swap? (sysstat)
sudo apt install -y sysstat
vmstat 1 5 # kolommen r (wachtrij), si/so (swap in/out), wa (I/O-wait)
iostat -xz 1 3 # %util per schijf, await in ms
# 3. Schijf: bytes én inodes
df -h --output=target,pcent,avail | sort -k2 -rn | head
df -i | awk 'NR==1 || $5+0 > 80'
# 4. Wat faalde er?
systemctl --failed
journalctl -p err -b --no-pager | tail -30
# 5. Werd er iets doodgeschoten door de OOM-killer?
journalctl -k -b | grep -iE 'out of memory|oom-kill' | tail
Twee dingen die beginners hier verkeerd lezen:
free -mtoont "free" bijna altijd laag. Kijk naar de kolom available. Linux gebruikt vrij geheugen als page cache en geeft dat terug wanneer nodig.load averageis geen percentage. Een load van 4 op een 8-core machine is rustig; op een 2-core machine betekent het dat er permanent processen staan te wachten. Vergelijk altijd metnproc.
Stap 2: zet historie aan (sysstat)
Zonder historie kun je nooit zeggen "dit is sinds dinsdag". sysstat verzamelt elke 10 minuten een snapshot en bewaart standaard 28 dagen.
sudo apt install -y sysstat
# Ubuntu 24.04 en Debian 12 gebruiken systemd-timers:
sudo systemctl enable --now sysstat-collect.timer sysstat-summary.timer
# Op oudere Debian/Ubuntu: zet ENABLED="true" in /etc/default/sysstat
# Vanaf morgen kun je terugkijken:
sar -u # CPU vandaag, per 10 min
sar -r # geheugen
sar -d -p # schijf-I/O per device
sar -n DEV # netwerk per interface
sar -u -f /var/log/sysstat/sa12 # de 12e van deze maand
Wil je 90 dagen? Zet HISTORY=90 in /etc/sysstat/sysstat. Het kost een paar MB per maand.
Stap 3: de vier metingen die er toe doen
Je kunt honderd dingen meten. Dit zijn de vier waarvan de afwezigheid je een incident kost:
| Meting | Waarom | Drempel die werkt |
|---|---|---|
| Schijfvulling en de richting | Volle schijf = database stopt, logs stoppen, updates falen | > 85 % óf "vol binnen 7 dagen" op basis van groei |
| Failed units + reboot-required | Een service die niet opkwam na een update merk je pas bij de klant | systemctl --failed ≠ 0, of /var/run/reboot-required bestaat > 3 dagen |
| OOM-kills | Het geheugenlek van vandaag is de outage van volgende week | ≥ 1 OOM-kill in 24 u |
| Heartbeat | De server zelf is weg, dus meldt hij niets | Geen ping in 5 min |
Let op wat er niet in staat: "CPU > 90 %". Een backup, een apt upgrade, een nachtelijke logrotate met compressie, een cron die een rapport bouwt — allemaal 100 % CPU, allemaal normaal. Die alert leert je binnen een week te negeren, en dan mis je de echte. Alert op symptomen (wachtrijen, I/O-wait boven 30 % gedurende 10 minuten, responstijd) of op afwijking van het normale patroon voor dat uur, niet op een absoluut getal.
Stap 4: een cron-script dat je telefoon aanspreekt
Dertig regels, geen dependencies buiten curl. Push gaat naar ntfy — self-hostbaar, gratis, EU-hostbaar. Vervang NTFY door je eigen topic.
sudo tee /usr/local/sbin/healthcheck.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
# Draait elke 10 min via cron. Meldt alleen wat afwijkt.
NTFY="https://ntfy.example.be/servers"
HOST=$(hostname -s)
ALERTS=()
# Schijf > 85 % (bytes of inodes), tmpfs uitgesloten
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')
# Failed units
FAILED=$(systemctl --failed --no-legend | awk '{print $1}' | tr '\n' ' ')
[ -n "$FAILED" ] && ALERTS+=("failed: $FAILED")
# Reboot vereist sinds > 3 dagen
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 laatste 24 u
OOM=$(journalctl -k --since "24 hours ago" --no-pager | grep -ci 'out of memory')
[ "$OOM" -gt 0 ] && ALERTS+=("oom-kills: $OOM")
# Load > 2x cores, 15-min gemiddelde (dus geen korte piek)
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
Test met een kunstmatige fout: sudo systemctl start nonexistent.service faalt niet zichtbaar, dus gebruik sudo systemctl mask cron && sudo systemctl restart cron — dat levert een failed unit op. Vergeet niet te unmask.
Heartbeat: de server die niets meer zegt
Bovenstaand script kan niet melden dat de server zelf weg is. Daarvoor heb je een tweede machine (of je laptop) die verwacht dat er iets binnenkomt. Simpelste vorm: het script doet elke 10 minuten een curl naar een ntfy-topic heartbeat-$HOST, en een cron op een andere host controleert of de laatste boodschap ouder is dan 15 minuten via curl "https://ntfy.example.be/heartbeat-$HOST/json?poll=1&since=15m". Het is knullig, en het werkt.
Stap 5: schijfgroei voorspellen in plaats van ontdekken
"85 %" op een schijf die 1 % per maand groeit is geen probleem. "60 %" op een schijf die 5 % per dag groeit is over acht dagen een outage. Met sar -F (Ubuntu 24.04+) of met je eigen logje bereken je de helling:
# Log elke dag de vulling
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
# Na een week: bytes per dag en dagen tot vol
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 "krimpt of stabiel"; exit}
printf "groei %.1f MB/dag, vol over %.0f dagen\n", slope/1e6, (total-y[n])/slope
}' /var/log/diskgrowth.log
Dat is een lineaire regressie in awk. Niet elegant, wel voldoende om een aankoop of een cleanup twee weken vooruit te plannen.
Valkuilen
- journald eet je schijf op.
journalctl --disk-usageverrast mensen. ZetSystemMaxUse=500Min/etc/systemd/journald.confensystemctl restart systemd-journald. dfziet verwijderde-maar-open bestanden niet. Een logbestand van 20 GB dat is verwijderd terwijl nginx het nog open heeft, blijft ruimte innemen.sudo lsof +L1toont ze; een reload van het proces geeft de ruimte vrij.- Snapshots en
/boot. LVM-snapshots en oude kernels vullen/boottot eenapt upgradefaalt. Neem/bootop in de disk-check en draaiapt autoremove --purgeregelmatig. - Tijdzone in cron.
crondraait in de systeemtijdzone; je ntfy-berichten ensarook. Als de server in UTC staat en jij in Brussel kijkt, klopt "om 3 uur" niet.timedatectlvertelt het. - Alerts zonder eigenaar. Een script dat pusht naar een topic waar niemand meer op geabonneerd is, is geen monitoring. Zet in de kalender: elk kwartaal een testalert.
Wat je hiermee nog niet hebt
Dit werkt uitstekend voor één tot vijf servers. Daarna loop je tegen dezelfde vier muren:
- Geen historie over hosts heen.
sarkijkt per machine. "Welke van mijn twintig servers groeit het snelst?" is een for-loop over ssh, elke keer weer. - Geen deduplicatie. Een schijf op 86 % levert elke 10 minuten een push op tot iemand ingrijpt. Na een dag negeert iedereen het topic.
- Geen baseline. Het script weet niet dat deze host op dinsdagnacht altijd load 6 heeft door de backup. Jij wel, maar je vervanger niet.
- Geen bewijs. Een NIS2- of ISO 27001-auditor vraagt "hoe weet je dat je monitoring werkt?" en een cron-bestand is daarop een zwak antwoord.
Zo doet monsys het
De monsys-agent (één statisch Rust-binary, geen dependencies) meet dezelfde dingen — CPU, geheugen, schijf per mount, netwerk per NIC, failed units, OOM-kills, reboot-required — elke 15 seconden, en stuurt geaggregeerde signalen naar de hub. De hub bouwt per host een uur-van-dag baseline zodat je kunt alerteren op afwijking in plaats van op een absoluut getal, dedupliceert alerts tot één open rij per oorzaak, en houdt 13 maanden historie bij voor capaciteitsvragen. Heartbeat-stilte is een aparte detectie, met onderscheid tussen "even weg" en "al dagen stil".
De eerste vijf servers zijn gratis, voor altijd. Installeren is één regel: curl -fsSL https://get.monsys.ai/install.sh | sudo bash.
FAQ
Is 90 % CPU-gebruik een probleem?
Op zichzelf niet. Een server die zijn CPU gebruikt doet zijn werk. Het wordt een probleem als er tegelijk een wachtrij ontstaat (kolom r in vmstat structureel groter dan het aantal cores) of als de responstijd van je applicatie stijgt. Alert op die symptomen, niet op het percentage.
Heb ik Prometheus of Grafana nodig voor een paar servers?
Nee. Voor minder dan vijf servers geeft sysstat plus een cron-script met push-notificaties je 90 % van de waarde voor 5 % van het onderhoud. Prometheus wordt interessant wanneer je dashboards over meerdere hosts heen wilt of applicatie-metrics gaat scrapen.
Werkt dit ook op Debian 12?
Ja, alle commando's in dit artikel zijn getest op Debian 12 en Ubuntu 24.04. Het enige verschil is de naam van sommige units; sysstat-collect.timer bestaat op beide.
Geschreven door het monsys-team — sysadmins die dit dagelijks doen.
Zelf gedaan? Laat monsys het bijhouden.
Alles uit deze how-to draait in monsys als doorlopende check, met historie, alerts en audit-bewijs. 5 servers gratis, EU-gehost in België, geïnstalleerd in 60 seconden.