Terug naar de blog

Systemd-service start niet? Zo los je het op

14 september 2026

Een systemd-service die niet start is vrijwel nooit mysterieus. Draai systemctl status <unit> en lees dan de laatste 50 journalregels van die unit met journalctl -u <unit> -n 50 --no-pager — met die twee noemt één van vijf oorzaken de boosdoener meestal letterlijk: een fout pad, een ontbrekende binary, verkeerde permissies, een SELinux- of AppArmor-weigering, of een syntaxfout in de unit-file. De faalreden staat in het log; de fixes hieronder zijn niets meer dan patroonherkenning.

Hoe zie ik waarom een systemd-service faalde?

Eerst status, dan journal:

systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager

status geeft je de toestand (inactive (dead), failed (exit-code), activating (auto-restart)) en de laatste paar logregels. De journal geeft je het hele verhaal: stdout, stderr en systemds eigen klachten over de unit.

Faalde de unit eerder en wil je het verslag van die run, voeg dan -b toe voor de huidige boot of --since today:

journalctl -u myapp.service -b --no-pager

Voor de volledige gereedschapskist — boots, prioriteiten, live volgen — zie het journalctl cheat sheet. Zelfde spiergeheugen.

Nog een paar dat loont te kennen:

systemctl list-units --failed
systemctl reset-failed myapp.service

De eerste zet elke rode unit op de doos op een rij. De tweede wist de failed-status nadat je het verholpen hebt — cosmetisch, maar het voorkomt dat statuspagina’s vals alarm slaan.

Wat zijn de meest voorkomende oorzaken?

Zodra het log het symptoom benoemt, is de oorzaak bijna altijd een van deze vijf:

Log zegtWaarschijnlijke oorzaakOplossing
status=203/EXECVerkeerd ExecStart=-pad of ontbrekende interpreterAbsoluut pad, chmod +x, shebang controleren
status=203/EXEC bij een scriptScript heeft CRLF-regeleinden of een fouten shebangdos2unix script.sh, eerste regel fixen
status=1/FAILURE, geen app-logWerkmap of omgevingsvariabele ontbreektZet WorkingDirectory=, voeg Environment= toe
Permission deniedUser kan bestanden niet lezen of de poort niet bindenEigendom fixen; poorten onder 1024 vereisen AmbientCapabilities=CAP_NET_BIND_SERVICE of root
Unit is maskedIemand draaide systemctl masksystemctl unmask myapp.service
Bewerken van de unit-file ‘doet niets’Daemon niet herladensystemctl daemon-reload

De 203/EXEC-familie verdient een eigen noot, want dit is de oorzaak die middagen opeet. Systemd gebruikt niet je shell om ExecStart= te starten. Dat betekent:

# Wrong — no shell, ~ never expands, no PATH lookup
ExecStart=~/app/run.sh

# Right
ExecStart=/opt/app/run.sh

En het script zelf moet uitvoerbaar zijn en met een echte shebang beginnen (#!/bin/bash of #!/usr/bin/env bash). Een script dat het prima doet in je terminal maar onder systemd faalt met 203 is bijna altijd een van: niet uitvoerbaar, CRLF-einden, een shebang die nergens heenwijst, of een relatief pad.

Waarom start hij handmatig maar niet bij het booten?

De klassieke volgordebug. Toont het log storingen vlak na de boot, maar start de unit prima als je ‘m met de hand systemctl start, dan verliest je service een race — hij grijpt naar het netwerk, een gemounte schijf of een database voordat dat ding bestaat.

De fix is dependencies uitspreken in plaats van hopen:

[Unit]
After=network-online.target postgresql.service
Wants=network-online.target

[Service]
ExecStartPre=/usr/bin/test -f /opt/app/config.toml

After= ordent de start; Wants= laat systemd de dependency echt opstarten. network-online.target werkt alleen als de network-wait-service op je distro aanstaat, dus controleer systemctl is-enabled NetworkManager-wait-online.service (of het systemd-networkd-equivalent). De ExecStartPre=-guard is een goedkope, eerlijke manier om luid te falen met een leesbare boodschap in plaats van een stack trace.

Een tweede variant: de service start bij de boot maar sterft meteen. Zoek naar wat je interactieve omgeving had en de boot niet — PATH-verschillen, een virtualenv, een HOME. Zet wat je nodig hebt expliciet:

[Service]
Environment="PATH=/opt/app/venv/bin:/usr/bin"
User=appuser
WorkingDirectory=/opt/app

Waarom logt mijn service niet naar de journal?

Als journalctl -u niets toont, controleer drie dingen op volgorde:

  1. StandardOutput= en StandardError= in de unit — die moeten journal (de standaard) of journal+console zijn. Iemand kan ze op null hebben gezet.
  2. De app schrijft naar een bestand in plaats van stdout. Systemd vangt alleen stdout/stderr af; bestandsschrijvers omzeilen de journal volledig. Richt de app op stdout of lees het bestand.
  3. Opslaglimieten lieten oude regels vallen: journalctl --disk-usage, en SystemMaxUse= in /etc/systemd/journald.conf als de journal stikt.

Voor het debuggen van de start zelf verslaat niets het droppen van een shell in de bootcontext:

[Service]
ExecStart=/bin/bash -c 'exec /opt/app/bin/server 2>&1'

Of, voor echte mysteries, draai het exacte ExecStart=-commando als de unit-user in een shell — de meeste omgevingsverschillen drijven in de eerste tien seconden boven.

Hoe laat ik hem automatisch herstarten na een crash?

Standaardbeleid is Restart=no: een gecrashte service blijft dood en je hoort het van een gebruiker. Fix dat per service:

[Service]
Restart=on-failure
RestartSec=5
InstellingHerstart wanneer
no (standaard)Nooit
on-failureNon-zero exit, signaal, timeout
alwaysElke exit, zelfs een schone
on-watchdogAlleen watchdog-timeout

Combineer Restart=on-failure met een start-rate-guard zodat een crashloop de doos niet blijft hameren: StartLimitIntervalSec= en StartLimitBurst= in het [Unit]-blok. Vijf storingen in zestig seconden moeten een mens wakker maken, geen CPU draaiend houden.

Richt je dit in als geplande job in plaats van als daemon, weeg dan eerst cron vs systemd-timer — timers geven je journal-logging en afhankelijkheidsvolgorde gratis, precies waar dit artikel steeds naar grijpt.

De checklist van 60 seconden

  1. systemctl status <unit> — lees de toestand en de laatste regels.
  2. journalctl -u <unit> -n 50 --no-pager — vind de echte fout.
  3. 203/EXEC? Fix pad, shebang, permissies. Permission denied? Fix user en bestandseigendom.
  4. Faalt alleen bij de boot? Voeg After=/Wants=network-online.target en een ExecStartPre=-guard toe.
  5. Unit-file aangepast? systemctl daemon-reload && systemctl restart <unit>.
  6. Voeg Restart=on-failure toe zodat de volgende crash zichzelf aankondigt in plaats van te verstoppen.

De meeste ‘systemd is ingewikkeld’-momenten beperken zich tot: de fout stond de hele tijd in de journal. Lees ‘m vóór je de unit-file bewerkt, niet erna.

FAQ

Hoe zie ik waarom een systemd-service faalde?

systemctl status <unit> voor de samenvatting, journalctl -u <unit> -e voor de echte foutregels.

Wat betekent exit-code 203 EXEC?

systemd kon het binaire bestand niet uitvoeren — verkeerd pad, ontbrekende interpreter of geen exec-bit. Het ExecStart-pad moet absoluut zijn.

Waarom werkt mijn service handmatig maar faalt hij in systemd?

Andere omgeving: geen HOME, andere PATH, andere user of cwd. Zet User=, WorkingDirectory= en Environment= expliciet.

— mrsaynothing

— mrsaynothing

Veldnotities over AI, Linux en self-hosting.

Bespreek deze post op dev.to dev.to ↗

De volgende how-to per e-mail

Eén e-mail per post. Fix het en ga door.

self-hosted · geen derden · uitschrijven met één klik

wat is dit?

GGUF-kwantisatie: welk niveau moet je kiezen?

Schrijf je dit met plezier? Dit bouw ik professioneel. huur me in