systemd – Dienste unter Linux verwalten
systemd ist das Init-System moderner Linux-Distributionen. Lerne systemctl, journalctl, eigene Service-Units und Troubleshooting im IT-Alltag.
Was ist systemd?
systemd ist das Init-System und der Service-Manager, der auf praktisch allen modernen Linux-Distributionen läuft – Ubuntu, Debian, RHEL, Fedora, openSUSE, Arch und viele mehr. Es ist der erste Prozess, den der Kernel startet (PID 1), und damit zuständig für alles, was danach kommt: Dienste hochfahren, Mounts einrichten, Logs sammeln und das System in einen definierten Zustand bringen.
Vor systemd gab es SysVinit mit Shell-Skripten in /etc/init.d/. systemd hat das weitgehend abgelöst und bringt einige klare Vorteile mit:
| Merkmal | SysVinit | systemd |
|---|---|---|
| Parallelisierung | Kaum (sequenziell) | Vollständig parallel |
| Abhängigkeiten | Manuell in Skripten | Deklarativ in Unit-Dateien |
| Logging | Syslog / Textdateien | journald (strukturiert, durchsuchbar) |
| Restart-Logik | Externes Skript nötig | Eingebaut (Restart=on-failure) |
| Aktivierungsarten | Beim Booten | Boot, Socket, Pfad, Timer, D-Bus |
Unit-Typen verstehen
systemd verwaltet sogenannte Units – das sind Konfigurationsdateien, die beschreiben, was systemd managen soll. Der Dateityp ergibt sich aus der Endung:
| Endung | Zweck |
|---|---|
.service | Dienste und Daemons (nginx, sshd, postgresql, …) |
.target | Synchronisationspunkte / Systemzustände (entspricht alten Runleveln) |
.timer | Zeitgesteuerte Ausloesungen (Alternative zu cron) |
.socket | Socket-Aktivierung (Dienst startet erst bei eingehender Verbindung) |
.mount | Einhaengepunkte im Dateisystem |
.path | Datei- oder Verzeichnisueberwachung |
.slice | Ressourcengruppen (cgroups) |
Im IT-Alltag wirst du fast immer mit .service und gelegentlich mit .timer zu tun haben.
Unit-Dateien liegen an diesen Orten (Prioritaet von oben nach unten):
/etc/systemd/system/ # Eigene / Administrator-Units (hoechste Prioritaet)
/run/systemd/system/ # Laufzeit-generierte Units
/usr/lib/systemd/system/ # Vom Paketmanager installierte Units
Willst du eine Paket-Unit anpassen, ohne sie zu ueberschreiben (damit Updates sie nicht zuruecksetzen), nutze Drop-in-Dateien:
# Erstellt automatisch ein Drop-in-Verzeichnis
sudo systemctl edit nginx.service
# Oeffnet Editor → schreibe nur die zu ueberschreibenden Sektionen
# Datei landet in: /etc/systemd/system/nginx.service.d/override.conf
Dienste verwalten mit systemctl
systemctl ist das zentrale Werkzeug fuer alles rund um systemd-Dienste.
Status und Zustand pruefen
# Detaillierter Status inkl. letzter Log-Zeilen
systemctl status nginx
# Kurze Abfragen (Exit-Code 0 = aktiv/enabled, 1 = nicht)
systemctl is-active nginx
systemctl is-enabled nginx
systemctl is-failed nginx
# Alle Services anzeigen
systemctl list-units --type=service
# Nur fehlgeschlagene
systemctl list-units --type=service --state=failed
# Alle Units inkl. inaktiver
systemctl list-units --type=service --all
Die Ausgabe von systemctl status nginx zeigt dir sofort den wichtigsten Kontext:
● nginx.service - A high performance web server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Mon 2026-06-23 08:12:33 UTC; 2h 14min ago
Process: 1234 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
Main PID: 1238 (nginx)
Tasks: 3 (limit: 4678)
Memory: 6.1M
CPU: 89ms
CGroup: /system.slice/nginx.service
├─1238 nginx: master process
└─1239 nginx: worker process
Starten, Stoppen, Neustarten
# Starten / Stoppen
sudo systemctl start nginx
sudo systemctl stop nginx
# Neustart (stop + start)
sudo systemctl restart nginx
# Konfiguration neu laden – ohne Unterbrechung (wenn der Dienst das unterstuetzt)
sudo systemctl reload nginx
# Reload wenn moeglich, sonst restart
sudo systemctl reload-or-restart nginx
Autostart beim Booten steuern
# Autostart aktivieren (symlink nach /etc/systemd/system/)
sudo systemctl enable nginx
# Autostart aktivieren UND sofort starten (der Normalfall beim Einrichten)
sudo systemctl enable --now nginx
# Autostart deaktivieren
sudo systemctl disable nginx
# Dienst sperren – kann nicht gestartet werden (auch nicht als Abhaengigkeit)
sudo systemctl mask nginx
sudo systemctl unmask nginx
Targets – die Ersatz-Runlevel
Targets sind Synchronisationspunkte, die einen bestimmten Systemzustand repraesentieren:
| Target | Entspricht | Bedeutung |
|---|---|---|
poweroff.target | Runlevel 0 | System herunterfahren |
rescue.target | Runlevel 1 | Single-User / Rettungsmodus |
multi-user.target | Runlevel 3 | Mehrbenutzerbetrieb ohne GUI |
graphical.target | Runlevel 5 | Mehrbenutzerbetrieb mit GUI |
reboot.target | Runlevel 6 | Neustart |
# Standard-Target anzeigen
systemctl get-default
# Standard-Target setzen (Server: meist multi-user.target)
sudo systemctl set-default multi-user.target
# In ein Target wechseln (sofort, ohne Neustart)
sudo systemctl isolate rescue.target
Logs mit journalctl lesen
systemd protokolliert alle Dienst-Ausgaben in journald – einem strukturierten, binaeren Log-System. Das Werkzeug dafuer ist journalctl.
Grundlegende Abfragen
# Alle Logs (beginnt am Anfang – oft sehr viel)
journalctl
# Logs eines bestimmten Dienstes
journalctl -u nginx
# Live-Ausgabe (wie tail -f)
journalctl -u nginx -f
# Letzter Boot
journalctl -b
# Vorletzter Boot
journalctl -b -1
# Alle verfuegbaren Boots auflisten
journalctl --list-boots
Zeitbasiertes Filtern
# Letzte Stunde
journalctl -u nginx --since "1 hour ago"
# Zeitraum angeben
journalctl -u nginx --since "2026-06-23 08:00" --until "2026-06-23 10:00"
# Heute
journalctl -u nginx --since today
# Letzte 50 Zeilen
journalctl -u nginx -n 50
Nach Prioritaet filtern
# Nur Fehler und schlimmer (emerg, alert, crit, err)
journalctl -p err
# Nur Warnungen und schlimmer
journalctl -p warning
# Kernel-Meldungen
journalctl -k
Ausgabeformat anpassen
# Kompakte Ausgabe (eine Zeile pro Eintrag)
journalctl -u nginx -o short
# JSON (maschinell lesbar)
journalctl -u nginx -o json-pretty
# Nur die Nachricht
journalctl -u nginx -o cat
# Nach Text suchen (grep-aehnlich)
journalctl -u nginx -g "error"
Speicherplatz verwalten
# Aktuelle Groesse des Journals
journalctl --disk-usage
# Altes Journal loeschen (aelter als 2 Wochen)
sudo journalctl --vacuum-time=2weeks
# Journal auf maximale Groesse begrenzen
sudo journalctl --vacuum-size=500M
Eigenen Dienst erstellen
Das ist eine der nuetzlichsten Faehigkeiten im Linux-Betrieb: Eigene Skripte oder Applikationen als systemd-Dienst verwalten. Damit laeuft deine App beim Booten automatisch, startet bei Absturz neu und schreibt Logs direkt ins Journal.
Schritt-fuer-Schritt-Anleitung
1. Service-Datei erstellen:
sudo nano /etc/systemd/system/mein-dienst.service
2. Inhalt der Unit-Datei:
[Unit]
Description=Meine Node.js-Applikation
Documentation=https://wiki.firma.ch
# Erst starten wenn Netzwerk verfuegbar und PostgreSQL laeuft
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
# Als welcher User soll der Dienst laufen? NIE root, ausser zwingend noetig
User=nodeapp
Group=nodeapp
WorkingDirectory=/opt/nodeapp
# Umgebungsvariablen direkt oder aus Datei
Environment=NODE_ENV=production
EnvironmentFile=/etc/nodeapp/env
# Der eigentliche Startbefehl
ExecStart=/usr/bin/node /opt/nodeapp/server.js
# Optional: Vor dem Start pruefen (z.B. Konfigtest)
# ExecStartPre=/opt/nodeapp/check-config.sh
# Neustart bei Fehler (nicht bei bewusstem Stop)
Restart=on-failure
RestartSec=5s
# Nicht mehr als 3 Neustarts in 60 Sekunden (Crash-Loop verhindern)
StartLimitBurst=3
StartLimitIntervalSec=60s
# Haertungsoptionen (Security Hardening)
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/nodeapp /var/log/nodeapp
[Install]
WantedBy=multi-user.target
3. Dienst aktivieren:
# systemd informieren dass neue Unit-Dateien vorhanden sind
sudo systemctl daemon-reload
# Aktivieren und starten
sudo systemctl enable --now mein-dienst
# Pruefen ob alles laeuft
systemctl status mein-dienst
journalctl -u mein-dienst -f
Unit-Sektionen im Ueberblick
[Unit] – Metadaten und Abhaengigkeiten:
| Option | Bedeutung |
|---|---|
Description= | Beschreibung (erscheint in systemctl status) |
After= | Erst starten nach diesen Units (Reihenfolge) |
Wants= | Weiche Abhaengigkeit (Unit fehlt → kein Fehler) |
Requires= | Harte Abhaengigkeit (Unit fehlt → Fehler) |
ConditionPathExists= | Nur starten wenn Pfad existiert |
[Service] – Wie der Dienst laeuft:
| Option | Bedeutung |
|---|---|
Type=simple | Prozess laeuft im Vordergrund (Standard) |
Type=forking | Prozess forkt sich selbst (alte Daemons) |
Type=oneshot | Einmaliger Befehl (z.B. Startup-Skript) |
Type=notify | Dienst meldet Bereitschaft aktiv (sd_notify) |
ExecStart= | Startbefehl (absoluter Pfad!) |
ExecStop= | Expliziter Stop-Befehl (sonst SIGTERM) |
Restart= | no, always, on-failure, on-abnormal |
RestartSec= | Wartezeit vor Neustart |
TimeoutStartSec= | Maximale Startzeit |
StandardOutput= | Wohin geht stdout (journal, null, file:/pfad) |
[Install] – Wann wird die Unit aktiv:
| Option | Bedeutung |
|---|---|
WantedBy=multi-user.target | Normaler Serverbetrieb (Standard fuer die meisten Dienste) |
WantedBy=graphical.target | Nur mit GUI |
systemd Timer als Cron-Ersatz
systemd-Timer sind eine leistungsstaerkere Alternative zu Cron-Jobs. Sie sind praeziser, haben bessere Logging-Integration und koennen mit anderen Units abhaengig gemacht werden.
Beispiel: Taeglich um 02:00 Uhr ein Backup-Skript ausfuehren
# 1. Service-Unit erstellen (die eigentliche Aktion)
sudo nano /etc/systemd/system/backup-daily.service
[Unit]
Description=Taeglich Backup ausfuehren
[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup.sh
# 2. Timer-Unit erstellen
sudo nano /etc/systemd/system/backup-daily.timer
[Unit]
Description=Backup taeglich um 02:00 Uhr
[Timer]
OnCalendar=*-*-* 02:00:00
# Nachholen wenn System zu dem Zeitpunkt aus war
Persistent=true
[Install]
WantedBy=timers.target
# 3. Timer aktivieren (nicht den Service!)
sudo systemctl daemon-reload
sudo systemctl enable --now backup-daily.timer
# Alle Timer und naechste Ausfuehrung anzeigen
systemctl list-timers
Troubleshooting – wenn Dienste nicht starten
Systematische Fehlersuche
# 1. Exakter Fehlerstatus
systemctl status mein-dienst
# 2. Vollstaendige Logs seit letztem Start
journalctl -u mein-dienst -b --no-pager
# 3. Nur Fehler des Dienstes
journalctl -u mein-dienst -p err
# 4. Syntaxpruefung der Unit-Datei
systemd-analyze verify /etc/systemd/system/mein-dienst.service
# 5. Abhaengigkeiten anzeigen
systemctl list-dependencies mein-dienst
# 6. Was haelt einen Dienst zurueck?
systemctl show mein-dienst | grep -E "ExecStart|Restart|User|WorkingDir"
Haeufige Fehler und Loesungen
Dienst startet nicht nach Aenderung der Unit-Datei:
# Vergessen, daemon-reload zu machen
sudo systemctl daemon-reload
sudo systemctl restart mein-dienst
“Failed to start: Unit not found”:
# Unit-Datei existiert nicht oder hat Tippfehler im Namen
ls /etc/systemd/system/*.service
systemctl list-unit-files | grep mein
“Permission denied” im Journal:
# Falscher User oder fehlende Berechtigungen auf Verzeichnisse
# Pruefen: Laeuft der Dienst unter dem richtigen User?
systemctl show mein-dienst | grep User
# Verzeichnis-Rechte pruefen
ls -la /opt/mein-app/
Dienst startet in Crash-Loop (staendig restart):
# Logs der fehlgeschlagenen Versuche anzeigen
journalctl -u mein-dienst --since "10 minutes ago"
# StartLimitBurst erreicht? Reset mit:
sudo systemctl reset-failed mein-dienst
Dienst wird mit systemctl start gestartet aber laeuft nicht weiter:
# Moeglicherweise Type=forking obwohl Prozess im Vordergrund laeuft
# oder ExecStart-Befehl endet sofort
# Teste den Befehl manuell im Terminal und schau was passiert
Systemd im KMU-Alltag: Praxisbeispiele
Samba/NFS nach Netzwerk starten
[Unit]
After=network-online.target
Wants=network-online.target
network-online.target ist staerker als network.target – es wartet bis das Netzwerk tatsaechlich erreichbar ist, nicht nur konfiguriert.
Monitoring-Check mit One-Shot
# /etc/systemd/system/check-disk.service
[Unit]
Description=Festplattenplatz pruefen
[Service]
Type=oneshot
ExecStart=/usr/local/bin/check-disk.sh
# /etc/systemd/system/check-disk.timer
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
SSH nach Konfigurations-Aenderung sicher neu laden
# Konfiguration pruefen (kein Typo der sshd abschiessen wuerde)
sudo sshd -t
# Nur wenn Test erfolgreich war, reload
sudo systemctl reload sshd
Verwandt: Mehr zu SSH-Absicherung unter SSH – Grundlagen.
Crosslinks
Wenn du noch nicht mit den Linux-Grundbefehlen vertraut bist, lies zuerst Linux – Grundbefehle fuer IT-Allrounder. Fuer zeitgesteuerte Aufgaben unter Linux findest du die cron-basierte Alternative unter Cron Jobs. Auf Windows-Servern uebernimmt der Task Scheduler eine aehnliche Rolle. Wer Docker-Container mit systemd verwalten will (z.B. als Podman-Integration), findet die Container-Grundlagen unter Docker – Container Grundlagen.
Weiterlernen
- systemd Dokumentation – freedesktop.org (offiziell)
- DigitalOcean: systemctl verwenden (Deutsch)
- DigitalOcean: journalctl verwenden (Deutsch)
- Red Hat Dokumentation: Working with systemd unit files (RHEL 9)
- SUSE: Introduction to systemd Basics
- contabo Blog: systemctl – Top-Befehle und Troubleshooting
Videos
Kommentare
Frage, Verbesserungsvorschlag oder eigene Erfahrung zu diesem Artikel? Schreib einen Kommentar. Neue Beiträge erscheinen nach kurzer Moderation.
- Lade Kommentare …