Zum Inhalt springen
Serverküche
Suche

Die Suche wird geladen … (nur in der veröffentlichten Seite verfügbar).

Grundlagen Schwierigkeit: Einsteiger

systemd verstehen: Units, Journal & Timer (statt Cron)

Dienste starten, Logs lesen, Aufgaben planen: Dieser Grundlagen-Guide erklärt systemd an echten Befehlen – inklusive eigenem Dienst und Timer statt Cron.

· 7 Min. Lesezeit ·Dauer: ca. 30 Minuten
Inhaltsverzeichnis

Jeder Dienst auf deinem Server – SSH, Docker, die Firewall – wird von systemd gestartet, überwacht und protokolliert. Wer systemd versteht, kann Ausfälle diagnostizieren, eigene Hintergrundjobs anlegen und geplante Aufgaben sauber automatisieren. Dieser Guide macht dich damit vertraut.

Was bauen wir?

Kein Dienst, sondern das Werkzeug, mit dem alle Dienste laufen: systemd (hier v257 auf Debian 13). Am Ende kannst du Dienste starten, stoppen und beim Booten aktivieren, ihre Logs mit journalctl lesen, einen eigenen Dienst als Unit-Datei anlegen und einen Timer bauen, der Cron ersetzt – mit dem entscheidenden Vorteil, dass er verpasste Läufe nachholen kann.

Voraussetzungen

🍳 Empfehlung Anzeige

VPS 1000 G12.5

4 vCore · 8 GB RAM · 128 GB SSD

ab 14,50 €/Monat

Die Befehle sind auf jedem systemd-Linux gleich – jeder Server genügt.

Zu netcup →

💶 1 Monat gratis:

Einmal einlösbar, gilt für VPS 1000 G12.5. Im Warenkorb einlösen →

💶 5,95 € Gutschein für netcup-Neukunden: immer gültig · nicht für Domains und VPS Lite

Alle netcup-Gutscheine →

Schritt für Schritt

Schritt 1: Units – das Grundkonzept

systemd verwaltet alles als Units. Die wichtigste Art ist der Service (.service) – ein Hintergrunddienst. Daneben gibt es u. a. Timer (.timer, geplante Ausführung), Sockets und Targets (Gruppen, grob vergleichbar mit Runlevels). Prüfe zuerst, welche Version läuft:

Terminal
systemctl --version
Ausgabe
systemd 257 (257.13-1~deb13u1)

Alle laufenden Dienste zeigt dir systemctl:

Terminal
systemctl list-units --type=service --state=running
Ausgabe
  containerd.service   loaded active running containerd container runtime
  cron.service         loaded active running Regular background program processing daemon
  docker.service       loaded active running Docker Application Container Engine
  fail2ban.service     loaded active running Fail2Ban Service
  ssh.service          loaded active running OpenBSD Secure Shell server

Jede Zeile ist eine Unit mit Ladezustand (loaded), Aktivzustand (active) und Unterzustand (running).

Schritt 2: Dienste steuern

Der wichtigste Befehl ist systemctl status. Er zeigt dir alles über einen Dienst – am Beispiel Docker:

Terminal
systemctl status docker
Ausgabe
● docker.service - Docker Application Container Engine
     Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; preset: enabled)
     Active: active (running) since Sun 2026-07-19 21:34:42 CEST; 4 days ago
   Main PID: 53379 (dockerd)
      Tasks: 93
     Memory: 282.8M (peak: 334.6M)

Zwei Zeilen sind entscheidend: Active: (läuft der Dienst gerade?) und in der Loaded:-Zeile das Wort enabled (startet er beim Booten automatisch?). Das sind zwei unabhängige Dinge – ein Dienst kann laufen, aber nicht beim Boot starten, und umgekehrt. Für Skripte fragst du beides knapp ab:

Terminal
systemctl is-active docker
systemctl is-enabled docker
Ausgabe
active
enabled

Die vier Befehle für den Alltag: systemctl start DIENST (jetzt starten), stop (jetzt anhalten), restart (neu starten, z. B. nach Konfigänderung) und reload (Konfiguration neu einlesen, ohne den Dienst zu unterbrechen – sofern er das unterstützt). Wichtig: start/stop wirken nur bis zum nächsten Reboot. Damit ein Dienst dauerhaft beim Booten startet, brauchst du enable:

Terminal
systemctl enable --now DIENST

enable schaltet den Autostart ein, --now startet den Dienst zusätzlich sofort – so sparst du dir den separaten start.

Schritt 3: Logs lesen mit journalctl

systemd sammelt die Ausgaben aller Dienste zentral im Journal. Statt in verstreuten Log-Dateien zu suchen, fragst du gezielt einen Dienst ab:

Terminal
journalctl -u docker -n 20

-u wählt die Unit, -n 20 zeigt die letzten 20 Zeilen. Die nützlichsten Varianten:

  • journalctl -u DIENST -f – live mitverfolgen (wie tail -f), ideal beim Debuggen.
  • journalctl -u DIENST --since "1 hour ago" – zeitlich eingrenzen.
  • journalctl -p err -b – nur Fehler seit dem letzten Boot (-b = aktueller Boot).

Genau das ist der erste Griff, wenn ein Dienst nicht startet: systemctl status DIENST für den Überblick, dann journalctl -u DIENST für die Details.

Schritt 4: Einen eigenen Dienst anlegen

Jetzt baust du selbst eine Unit. Beispiel: ein Backup-Skript, das systemd ausführen soll. Unit-Dateien für eigene Dienste liegen in /etc/systemd/system/. Lege backup-demo.service an:

INI
[Unit]
Description=Demo-Backup-Job

[Service]
Type=oneshot
ExecStart=/usr/bin/bash -c 'echo "Backup lief am $(date)" >> /var/log/backup-demo.log'

Der Abschnitt [Unit] beschreibt die Unit, [Service] sagt, was laufen soll. Type=oneshot ist der Typ für einmalige Aufgaben, die starten, ihre Arbeit tun und sich beenden (im Gegensatz zu Dauerdiensten wie docker). Nach dem Anlegen einer neuen Unit muss systemd sie einlesen:

Terminal
systemctl daemon-reload
systemctl start backup-demo.service

Prüfe das Ergebnis – oneshot-Dienste stehen nach getaner Arbeit korrekterweise auf inactive (dead):

Terminal
systemctl status backup-demo.service
Ausgabe
○ backup-demo.service - Demo-Backup-Job
     Loaded: loaded (/etc/systemd/system/backup-demo.service; static)
     Active: inactive (dead)

systemd[1]: Starting backup-demo.service - Demo-Backup-Job...
systemd[1]: backup-demo.service: Deactivated successfully.
systemd[1]: Finished backup-demo.service - Demo-Backup-Job.

Schritt 5: Timer statt Cron

Damit der Job regelmäßig läuft, koppelst du ihn an einen Timer – die systemd-Alternative zu Cron. Lege backup-demo.timer an (gleicher Name wie der Service, andere Endung):

INI
[Unit]
Description=Startet den Demo-Backup täglich

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target

OnCalendar bestimmt den Zeitplan (hier: täglich um 03:00 Uhr). Persistent=true ist der entscheidende Vorteil gegenüber Cron: War der Server zur geplanten Zeit aus, holt systemd den Lauf beim nächsten Start nach – ein verpasstes Backup fällt so nicht einfach aus. Aktiviere den Timer:

Terminal
systemctl daemon-reload
systemctl enable --now backup-demo.timer

Wundere dich nicht, wenn der Job direkt nach dem enable einmal läuft: Weil Persistent=true gesetzt ist und systemd noch keinen früheren Lauf gespeichert hat, holt es den vermeintlich verpassten Termin sofort nach. Danach greift der normale Zeitplan.

Alle aktiven Timer zeigt systemctl list-timers; mit einem Unit-Namen als Argument siehst du nur deinen eigenen:

Terminal
systemctl list-timers backup-demo.timer
Ausgabe
NEXT                             LEFT LAST                           PASSED UNIT              ACTIVATES
Fri 2026-09-04 03:00:00 CEST 1h 24min Fri 2026-09-04 01:35:46 CEST 81ms ago backup-demo.timer backup-demo.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.

NEXT und LEFT sagen dir, wann der Timer das nächste Mal feuert, LAST und PASSED, wann er es zuletzt getan hat – hier gerade eben, durch das Nachholen.

OnCalendar-Ausdrücke testen

Bevor du einen komplizierten Zeitplan aktivierst, prüfe ihn mit systemd-analyze calendar "Mon *-*-* 09:00:00" – das zeigt dir die nächsten Ausführungszeitpunkte, ohne etwas zu starten. So vermeidest du Timer, die nie oder zur falschen Zeit feuern.

Genau dieses Muster – ein oneshot-Service plus Timer – nutzen die Restic-Backups der Serverküche. Du hast damit das Werkzeug für jede wiederkehrende Wartungsaufgabe in der Hand.

Wenn es nicht funktioniert

systemctl start schlägt fehl, status zeigt status=203/EXEC. systemd konnte das Programm aus ExecStart nicht ausführen; im Journal steht dazu Unable to locate executable. Entweder stimmt der Pfad nicht, oder der Datei fehlt das Ausführbar-Bit (chmod +x). Ohne führenden / sucht systemd nur in /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin (nachzusehen mit systemd-path search-binaries-default) – ein eigenes Skript unter /opt oder /root musst du deshalb mit absolutem Pfad eintragen.

systemd warnt „The unit file, source configuration file or drop-ins of … changed on disk". Du hast eine Unit-Datei bearbeitet, aber systemd liest Änderungen nicht automatisch. Nach jeder Änderung an /etc/systemd/system/ gilt: systemctl daemon-reload.

Der Timer taucht in list-timers nicht auf. Er wurde nicht aktiviert. systemctl enable --now DIENST.timer – und daran denken, dass der Timer den Service auslöst, du also beide Dateien brauchst (.service und .timer).

systemctl enable antwortet „The unit files have no installation config". Der Unit fehlt der Abschnitt [Install] mit WantedBy=; in systemctl status erkennst du sie am static in der Loaded:-Zeile. Ohne [Install] weiß systemd nicht, wann die Unit automatisch starten soll – bei Timern gehört WantedBy=timers.target hinein.

Das Journal ist riesig / frisst Platz. Standardmäßig wächst es begrenzt, aber du kannst es beschneiden: journalctl --vacuum-time=14d löscht Einträge älter als 14 Tage, journalctl --disk-usage zeigt den Verbrauch.

Dein Problem ist nicht dabei? Alle Fehlermeldungen durchsuchen →

Wartung & Backups

  • Eigene Units gehören ins Backup. Alles unter /etc/systemd/system/ ist deine eigene Konfiguration und sollte im Restic-Backup liegen. Nach einem Server-Neuaufbau stellst du damit deine Dienste und Timer sofort wieder her (danach einmal daemon-reload und die Timer neu enablen).
  • Timer statt eigener Cron-Jobs. Wenn du ohnehin systemd nutzt, sind Timer die konsistentere Wahl: Sie laufen im Journal auf, holen verpasste Läufe nach (Persistent=true) und lassen sich mit systemctl status DIENST genauso überwachen wie jeder andere Dienst.
  • Failed-Units im Blick behalten. systemctl --failed listet Dienste, die abgestürzt sind – ein schneller Gesundheitscheck fürs System. Für echte Alarmierung meldet dir Uptime Kuma den Ausfall des Servers, während systemctl --failed die Ursache auf dem Host zeigt.

Feedback per E-Mail: feedback@serverkueche.de

Das könnte dir auch schmecken