Server-Administration

systemd verstehen: So steuerst du Dienste auf modernen Linux-Servern

systemd ist mehr als ein Ersatz für Init-Skripte: Units, Abhängigkeiten, Timer und Journal hängen zusammen. Wer nur systemctl start auswendig lernt, verschenkt genau die Automatisierung, für die systemd gebaut wurde.

5 Kapitel mit allen Befehlen
Administrator steckt ein Netzwerkkabel in einen Serverschrank
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Seit 1997 am Markt Präsenz & Live-Online 4,9 aus 503 Google-Bewertungen Auch Inhouse für dein Team
Worum es geht

Warum systemd oft erst beim ersten Ausfall wirklich verstanden wird

Im Alltag reichen start, stop, enable und status erstaunlich weit. Deshalb bleibt das Modell dahinter bei vielen Admins unscharf, bis ein Dienst nach dem Reboot nicht mehr hochkommt, ein Restart-Loop die Logs flutet oder eine Anwendung startet, bevor das Netzwerk oder das NFS-Mount bereit ist. Dann stellt sich heraus, dass systemd kein Ersatz für die alten Init-Skripte ist, sondern eine andere Denkweise: Statt einer festen Reihenfolge beschreibst du Abhängigkeiten und Zustände, und systemd entscheidet über die Parallelisierung.

Dazu kommt, dass systemd viel mehr ist als der Service-Manager. Ein Unit-Typ verwaltet Mounts, einer Sockets, einer Timer, einer Geräte, einer Ressourcengrenzen über cgroups. Wer nur .service kennt, baut Umwege: ein Cronjob statt eines Timers, ein Wrapper-Skript statt einer sauberen Dependency, ein selbst gebasteltes Logfile statt journald mit strukturierten Feldern. Das funktioniert eine Weile und fällt genau dann auf die Füße, wenn du unter Zeitdruck debuggen musst.

Typische Fehlerbilder wiederholen sich: Die Unit liegt im falschen Verzeichnis und wird von einem Paketupdate überschrieben, weil sie nicht als Drop-in unter /etc/systemd/system angelegt wurde. After= wird mit Requires= verwechselt, sodass die Reihenfolge stimmt, die Abhängigkeit aber fehlt oder umgekehrt. Der Type= passt nicht zum Verhalten des Prozesses, also gilt der Dienst als gestartet, obwohl er noch initialisiert. Und Restart=always verdeckt einen Konfigurationsfehler so lange, bis StartLimitBurst zuschlägt.

Miniatur-Szene: geöffneter Serverschrank mit Werkzeug, Patchpanel und grünem Uptime-Balken
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt

Vom Kernel bis zum laufenden Dienst

  1. 01 Kernel startet PID 1
  2. 02 default.target wird aufgelöst
  3. 03 Abhängigkeiten und Reihenfolge
  4. 04 Units starten parallel
  5. 05 Dienst läuft in eigener cgroup
  6. 06 journald sammelt Ausgabe
Was du mitnimmst

Das Modell in der richtigen Reihenfolge aufbauen

systemd wird beherrschbar, wenn du es von unten nach oben liest: erst die Unit als kleinste Einheit, dann die Beziehungen zwischen Units, dann die Targets als Zustände des Systems und zum Schluss die Beobachtbarkeit über journald. In dieser Reihenfolge gehen wir auch in den cmt-Kursen vor.

Unit-Typen unterscheiden und richtig wählen

service, socket, timer, mount, path, target und slice lösen jeweils ein eigenes Problem. Wenn du weißt, welcher Typ zuständig ist, ersparst du dir Wrapper-Skripte. Ein Socket, das den Dienst bei Bedarf aktiviert, ist etwas anderes als ein Dienst, der dauerhaft läuft, und ein Timer ist gegenüber einem Cronjob im Vorteil, weil er dieselbe Log- und Abhängigkeitsmechanik nutzt wie alles andere.

Eine eigene Unit sauber schreiben

Die drei Abschnitte [Unit], [Service] und [Install] haben klare Aufgaben. Entscheidend sind Type= (simple, exec, forking, oneshot, notify), ExecStart mit absolutem Pfad, User und Group, WorkingDirectory sowie eine Restart-Policy mit RestartSec und StartLimitIntervalSec. Eigene Units gehören nach /etc/systemd/system, Anpassungen an Distributions-Units als Drop-in via systemctl edit, danach systemctl daemon-reload.

Abhängigkeiten von Reihenfolge trennen

Before= und After= regeln ausschließlich die Reihenfolge, Requires=, Wants= und BindsTo= regeln, ob eine Unit überhaupt mitgestartet und bei Ausfall mitgerissen wird. Fast alle unerklärlichen Startprobleme entstehen daraus, dass beides vermischt wird. Mit systemd-analyze verify, systemctl list-dependencies und systemd-analyze critical-chain machst du das sichtbar, statt zu raten.

Targets statt Runlevel denken

multi-user.target, graphical.target, network-online.target und rescue.target sind keine durchnummerierten Runlevel, sondern Synchronisationspunkte. Wichtig ist der Unterschied zwischen network.target und network-online.target, an dem sich viele Dienste verschlucken, die zum Start bereits eine erreichbare Adresse brauchen.

journald als erste Anlaufstelle beim Debugging

journalctl -u dienst -b, --since, -p err und -f liefern in Sekunden das, wofür sonst mehrere Logdateien durchsucht werden. Du lernst, wann ein persistentes Journal unter /var/log/journal sinnvoll ist, wie Rotation und SystemMaxUse konfiguriert werden und wie sich das Journal parallel an einen bestehenden Syslog- oder Loki-Stack weiterreichen lässt.

Ressourcen und Absicherung über die Unit

cgroups sind in systemd direkt in der Unit erreichbar: MemoryMax, CPUQuota und TasksMax begrenzen einen Dienst, ohne dass du eine externe Lösung brauchst. Dazu kommen Sandbox-Optionen wie ProtectSystem, PrivateTmp, NoNewPrivileges und ReadWritePaths, mit denen ein Dienst deutlich weniger Angriffsfläche hat. systemd-analyze security zeigt dir, wo eine Unit noch offen ist.

Tutorial

Units, Timer und Journal im Griff

Die meisten Anleitungen hören nach systemctl start auf. Genau danach wird es interessant: eigene Units schreiben, Abhängigkeiten korrekt setzen, Timer statt Cron nutzen und im Journal gezielt suchen. Dieser Teil zeigt das an Beispielen, die du direkt übernehmen kannst.

01

Eine eigene Unit schreiben

Für jeden Dienst, der nicht aus einem Paket kommt, brauchst du eine Unit. Die drei Abschnitte sind schnell erklärt und der Rest ergibt sich daraus.

/etc/systemd/system/meinapp.service
[Unit]
Description=Meine Anwendung
Documentation=https://intern.firma.de/wiki/meinapp
# Erst starten, wenn Netzwerk und Datenbank bereit sind
After=network-online.target postgresql.service
Wants=network-online.target
Requires=postgresql.service
# Nach fünf Fehlstarts in 60 Sekunden aufgeben statt endlos zu versuchen.
# Beide Werte gehoeren in [Unit], in [Service] werden sie ignoriert.
StartLimitBurst=5
StartLimitIntervalSec=60

[Service]
Type=notify
User=meinapp
Group=meinapp
WorkingDirectory=/opt/meinapp
ExecStart=/opt/meinapp/bin/server --config /etc/meinapp/config.toml
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5s

[Install]
WantedBy=multi-user.target

After regelt nur die Reihenfolge, Requires die Abhängigkeit. Wer nur After setzt, startet zwar später, aber auch dann, wenn die Datenbank gar nicht läuft.

Die wichtigsten Type-Werte

TypeBedeutungWann
simpleProzess läuft im Vordergrund, gilt sofort als gestartetStandardfall, wenn die Anwendung nichts meldet
notifyAnwendung meldet Bereitschaft selbst über sd_notifySauberste Variante, wenn die Anwendung es unterstützt
forkingProzess spaltet sich ab, Eltern beendet sichKlassische Daemons, braucht PIDFile=
oneshotläuft einmal und endetWartungsaufgaben, meist zusammen mit einem Timer
Aktivieren und prüfen
sudo systemctl daemon-reload      # nach jeder Änderung an Unit-Dateien
sudo systemctl enable --now meinapp

systemctl status meinapp
systemctl cat meinapp             # zeigt die effektive Unit samt Drop-ins
systemd-analyze verify meinapp.service

systemctl cat ist der Befehl, den man am seltensten kennt und am häufigsten braucht: Er zeigt die zusammengesetzte Konfiguration inklusive aller Overrides.

02

Mitgelieferte Units anpassen, ohne sie zu überschreiben

Eine Unit aus einem Paket direkt zu bearbeiten ist ein Fehler: Beim nächsten Update ist die Änderung weg. Drop-ins lösen das sauber.

Override anlegen
# Öffnet einen Editor und legt die Datei an der richtigen Stelle an
sudo systemctl edit nginx

# Erzeugt /etc/systemd/system/nginx.service.d/override.conf
# Dort nur die Zeilen eintragen, die abweichen:
#   [Service]
#   LimitNOFILE=65535

# Vollständige Kopie zum Bearbeiten (selten nötig)
sudo systemctl edit --full nginx

# Was gilt jetzt wirklich?
systemctl show nginx -p LimitNOFILE

Bei Listen-Direktiven wie ExecStart musst du zuerst mit einer leeren Zuweisung zurücksetzen: ExecStart= und dann die neue Zeile. Sonst hängt systemd den Wert an und der Start schlägt fehl.

03

Timer statt Cron

Systemd-Timer haben gegenüber Cron drei Vorteile, die im Betrieb zählen: Sie holen verpasste Läufe nach, protokollieren ins Journal und erben alle Härtungsoptionen der zugehörigen Unit.

Zwei Dateien: .service und .timer
# /etc/systemd/system/backup.service
[Unit]
Description=Nächtliche Sicherung

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
# Bei Fehlschlag eine Meldung auslösen
OnFailure=meldung@%n.service

# /etc/systemd/system/backup.timer
[Unit]
Description=Sicherung täglich um 3 Uhr

[Timer]
OnCalendar=*-*-* 03:00:00
# Verpasste Läufe nachholen, wenn die Maschine aus war
Persistent=true
# Streuung, damit nicht alle Server gleichzeitig loslegen
RandomizedDelaySec=900

[Install]
WantedBy=timers.target

Aktiviert wird der Timer, nicht der Service: sudo systemctl enable --now backup.timer.

Prüfen und testen
# Wann läuft was das nächste Mal?
systemctl list-timers --all

# Zeitangabe verstehen und gegenprüfen
systemd-analyze calendar "*-*-* 03:00:00"
systemd-analyze calendar "Mon..Fri 08:00" --iterations=5

# Sofort auslösen, ohne auf die Uhrzeit zu warten
sudo systemctl start backup.service

# Was hat der letzte Lauf gemacht?
journalctl -u backup.service -n 50

systemd-analyze calendar ist die Absicherung gegen Tippfehler in der Zeitangabe. Eine falsche OnCalendar-Zeile führt sonst dazu, dass der Timer nie oder viel zu oft läuft.

04

Im Journal gezielt suchen

Das Journal kann mehr als journalctl -u dienst. Wer die Filter kennt, findet die relevante Zeile in Sekunden statt in Minuten.

Die nützlichsten Filter
# Nur der aktuelle Bootvorgang, nur Fehler und schlimmer
journalctl -b -p err

# Vorheriger Boot (nach einem unerwarteten Neustart)
journalctl -b -1 -p warning

# Zeitraum eingrenzen
journalctl --since "2026-07-20 08:00" --until "2026-07-20 09:30"
journalctl --since "1 hour ago" -u nginx

# Mehrere Units gemeinsam, chronologisch
journalctl -u nginx -u php8.2-fpm -f

# Nach Feldern filtern statt nach Text zu greppen
journalctl _UID=33 --since today
journalctl _COMM=sshd -p warning

# Maschinenlesbar für die Auswertung
journalctl -u nginx -o json-pretty --since today | jq -r '.MESSAGE'

Die Unterstrich-Felder sind vertrauenswürdige Metadaten, die systemd selbst setzt. Sie lassen sich vom Prozess nicht fälschen, anders als der Meldungstext.

05

Startzeit und Abhängigkeiten verstehen

Wenn ein Server lange braucht oder ein Dienst zu früh startet, liegt die Antwort fast immer in der Abhängigkeitskette.

Analysewerkzeuge
systemd-analyze                    # Gesamtdauer
systemd-analyze blame | head -15   # langsamste Units
systemd-analyze critical-chain     # der Pfad, der die Dauer bestimmt
systemd-analyze plot > start.svg   # grafische Übersicht

# Wer hängt von wem ab?
systemctl list-dependencies meinapp.service
systemctl list-dependencies --reverse postgresql.service

critical-chain ist aussagekräftiger als blame: Eine Unit kann lange dauern, ohne den Start zu verzögern, wenn parallel anderes läuft.

Wissen prüfen

Teste dich und finde deinen Weg

Bevor du einen Kurs buchst, lohnt sich eine ehrliche Standortbestimmung. Die Tests sind kostenlos und ohne Anmeldung.

Gut zu wissen

Häufige Fragen zu systemd-Grundlagen

Noch etwas offen? Wir sind ohne Warteschleife für dich da.

Frag uns direkt
Was ist der Unterschied zwischen einer Unit, einem Service und einem Target?
Die Unit ist der Oberbegriff für alles, was systemd verwaltet, und existiert in mehreren Typen. Ein Service ist die Unit-Art, die einen Prozess startet und überwacht. Ein Target ist eine Unit ohne eigenen Prozess, die andere Units gruppiert und damit einen Systemzustand beschreibt, etwa multi-user.target als Zustand mit allen Netzwerkdiensten, aber ohne grafische Oberfläche.
Warum startet mein systemd-Service nicht, obwohl das Kommando in der Shell funktioniert?
In den meisten Fällen liegt es an drei Punkten: Der Dienst läuft unter einem anderen Benutzer und einer anderen Umgebung als deine Shell, also fehlen PATH oder Umgebungsvariablen, ExecStart braucht einen absoluten Pfad und akzeptiert keine Shell-Syntax wie Pipes oder Variablenexpansion, und der gewählte Type= passt nicht zum Verhalten des Prozesses. Ein Prozess, der sich in den Hintergrund forkt, braucht Type=forking, sonst hält systemd ihn fälschlich für beendet. systemctl status und journalctl -u zeigen dir den tatsächlichen Exit-Code.
Soll ich Cronjobs auf systemd-Timer umstellen?
Für neue Aufgaben ist der Timer meistens die bessere Wahl, weil er dieselben Abhängigkeiten, Ressourcengrenzen und Logs nutzt wie jeder andere Dienst, weil Persistent=true verpasste Läufe nachholt und weil systemctl list-timers den nächsten Lauf transparent macht. Bestehende, stabile Cronjobs musst du nicht aus Prinzip migrieren. cron läuft auf allen gängigen Distributionen weiter.
Wie finde ich heraus, was den Systemstart verlangsamt?
systemd-analyze zeigt die Gesamtdauer getrennt nach Kernel und Userspace, systemd-analyze blame listet die Units nach Startdauer und systemd-analyze critical-chain zeigt die Kette, die tatsächlich kritisch war. Wichtig ist der Unterschied: Eine lange dauernde Unit ist nur dann ein Problem, wenn sie auch in der kritischen Kette liegt, denn systemd startet vieles parallel.
Muss ich für LPIC-1 oder RHCSA systemd können?
Ja, in beiden Zertifizierungen ist systemd fester Bestandteil. Für LPIC-1 gehört der Umgang mit systemctl, Unit-Dateien, Targets und journalctl zum Prüfungsstoff, und bei den Red-Hat-Prüfungen wird zusätzlich erwartet, dass du Dienste konfigurierst, dauerhaft aktivierst und Startprobleme selbst behebst. In den cmt-Kursen Linux Aufbaukurs: Administration und Systemmanagement (LPI02), LFS207 Linux System Administration Essentials und RH124 Red Hat System Administration I arbeitest du genau daran.

Zuletzt geprüft am 26. Juli 2026.

Das sagen Teilnehmer

Echte Stimmen aus unseren IT-Kursen

Die Schulung war genau das richtige, um mein Verständnis zu erweitern. Vielen Dank an den Trainer!
Rückmeldung aus dem Kurs „Linux Grundkurs (LPI01)“
Trainer gut und verständlich. Unterlagen nur zum lesen (keine Kopierfunktion). Wissenstransfer erfolgreich.
Rückmeldung aus dem Kurs „SUSE Linux Enterprise 15 High Availability Deployment – HAE311v15“
Persönlich für dich da

Deine Ansprechpartner

Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.

Yves Hoppe

Yves Hoppe

Weiterbildung & Beratung

Hilft dir, aus dem Linux-Programm den passenden Kurs oder Lernpfad zu finden.

Norbert Jansen

Norbert Jansen

Beratung & Inhouse

Plant mit dir Inhouse-Trainings, die exakt auf eure Systemlandschaft und Distributionen zugeschnitten sind.

Nächster Schritt

Du willst systemd nicht nur bedienen, sondern verstehen

In unseren Linux-Kursen baust du eigene Units, Timer und Drop-ins auf echten Systemen und analysierst Startprobleme mit systemd-analyze und journalctl, statt sie wegzustarten. Der Linux Aufbaukurs: Administration und Systemmanagement (LPI02) ist der direkte Einstieg, LFS207 und RH124 decken denselben Stoff im Linux-Foundation- beziehungsweise Red-Hat-Kontext ab. Alle Termine gibt es als Live-Online-Schulung und als Präsenzkurs, und wenn du unsicher bist, welcher Kurs zu deinem Stand passt, melde dich einfach bei uns.