systemd-Timer sind der moderne Ersatz für Cron auf Linux-Systemen. Sie bieten alles, was Cron kann — wiederkehrende und einmalige Zeitplanung — plus integriertes Logging, Abhängigkeitsverwaltung, Ressourcenkontrolle und die Möglichkeit, verpasste Ausführungen nachzuholen. Wenn Sie Linux-Server verwalten, bedeutet der Umstieg von Cron auf systemd-Timer weniger stille Fehler und deutlich bessere Transparenz darüber, was Ihre geplanten Aufgaben tun.

Diese Anleitung führt Sie durch das Erstellen von Timern von Grund auf, das Umwandeln bestehender Cron-Jobs und die Nutzung fortgeschrittener Funktionen wie zufällige Verzögerungen und persistente Zeitplanung.

Voraussetzungen

  • Ein Linux-System mit systemd (Ubuntu 16.04+, CentOS 7+, Debian 8+ oder jede moderne Distribution)
  • Root- oder sudo-Zugang
  • Grundlegende Vertrautheit mit systemctl und Unit-Dateien

Wie systemd-Timer funktionieren

Ein systemd-Timer besteht aus zwei Unit-Dateien:

  1. Eine .service-Unit — definiert, was ausgeführt wird (der eigentliche Befehl oder das Skript)
  2. Eine .timer-Unit — definiert, wann es ausgeführt wird (der Zeitplan)

Die Timer-Unit aktiviert die zugehörige Service-Unit nach Zeitplan. Beide Dateien müssen denselben Basisnamen haben (z. B. backup.service und backup.timer), es sei denn, Sie geben explizit eine andere Unit mit Unit= an.

Diese Trennung ist ein entscheidender Vorteil gegenüber Cron: Die Service-Unit kann unabhängig getestet, bei Fehlern neu gestartet und mit Standard-systemd-Werkzeugen inspiziert werden.

Ihren ersten Timer erstellen

Erstellen wir einen Timer, der ein Bereinigungsskript täglich um 2:00 Uhr morgens ausführt.

Schritt 1: Service-Unit erstellen

sudo nano /etc/systemd/system/daily-cleanup.service
[Unit]
Description=Daily temporary file cleanup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh

Type=oneshot teilt systemd mit, dass dieser Prozess bis zum Abschluss läuft und sich dann beendet — es ist kein dauerhaft laufender Daemon. Dies ist der richtige Typ für geplante Aufgaben.

Erstellen Sie das referenzierte Skript:

sudo tee /usr/local/bin/cleanup.sh > /dev/null << 'EOF'
#!/bin/bash
find /tmp -type f -mtime +7 -delete
find /var/log -name "*.gz" -mtime +30 -delete
echo "Cleanup completed at $(date)"
EOF
sudo chmod +x /usr/local/bin/cleanup.sh

Schritt 2: Timer-Unit erstellen

sudo nano /etc/systemd/system/daily-cleanup.timer
[Unit]
Description=Run daily cleanup at 2:00 AM

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

[Install]
WantedBy=timers.target

Wichtige Direktiven:

DirektiveZweck
OnCalendarKalenderbasierter Zeitplan (wie Cron)
Persistent=trueSofortige Ausführung, falls ein geplanter Lauf verpasst wurde (z. B. System war ausgeschaltet)
WantedBy=timers.targetErforderlich, damit systemctl enable funktioniert

Schritt 3: Aktivieren und starten

sudo systemctl daemon-reload
sudo systemctl enable --now daily-cleanup.timer

Schritt 4: Überprüfen

systemctl list-timers daily-cleanup.timer

Ausgabe:

NEXT                        LEFT          LAST PASSED UNIT                  ACTIVATES
Wed 2025-12-24 02:00:00 UTC 10h left      n/a  n/a   daily-cleanup.timer   daily-cleanup.service

Testen Sie den Service manuell, um zu bestätigen, dass er funktioniert:

sudo systemctl start daily-cleanup.service
journalctl -u daily-cleanup.service --no-pager -n 20

Die OnCalendar-Syntax verstehen

Die OnCalendar-Direktive verwendet ein flexibles Kalenderausdrucksformat:

Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde

Hier sind die gebräuchlichsten Muster:

ZeitplanOnCalendar-Ausdruck
Täglich um Mitternacht*-*-* 00:00:00
Jeden Montag um 9 UhrMon *-*-* 09:00:00
Erster jedes Monats*-*-01 00:00:00
Alle 15 Minuten*-*-* *:00/15:00
Werktags um 18 UhrMon..Fri *-*-* 18:00:00
Jeden 1. Jan und Jul*-01,07-01 00:00:00
Alle 2 Stunden*-*-* 00/2:00:00

Sie können Ausdrücke mit systemd-analyze calendar validieren:

systemd-analyze calendar "Mon..Fri *-*-* 09:00:00"
  Original form: Mon..Fri *-*-* 09:00:00
Normalized form: Mon..Fri *-*-* 09:00:00
    Next elapse: Mon 2025-12-29 09:00:00 UTC
       (in UTC): Mon 2025-12-29 09:00:00 UTC
       From now: 5 days left

Dies ist einer der größten Vorteile gegenüber Cron — Sie können Ihren Zeitplanausdruck überprüfen, bevor Sie ihn einsetzen.

Monotone Timer: Intervalle nach Ereignissen

Nicht alle Zeitpläne sind uhrzeitbasiert. Monotone Timer lösen relativ zu einem Ereignis aus:

[Timer]
OnBootSec=5min
OnUnitActiveSec=1h
DirektiveAuslöser
OnBootSecX Zeit nach dem Booten
OnStartupSecX Zeit nach dem Start von systemd
OnUnitActiveSecX Zeit nach der letzten Aktivierung des Timers
OnUnitInactiveSecX Zeit nach dem letzten Abschluss des Services

Dies ist nützlich für Zustandsprüfungen, Metrik-Erfassung oder jede Aufgabe, die in festen Intervallen laufen soll, unabhängig von der Uhrzeit.

Beispiel — Zustandsprüfung alle 5 Minuten, beginnend 1 Minute nach dem Booten:

[Unit]
Description=Periodic health check

[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
AccuracySec=10s

[Install]
WantedBy=timers.target

AccuracySec=10s verkleinert das standardmäßige 1-Minuten-Zusammenfassungsfenster, sodass Ihr Timer näher an genau alle 5 Minuten auslöst.

Fortgeschrittene Funktionen

Zufällige Verzögerung

Verhindern Sie, dass mehrere Server gleichzeitig auf dieselbe Ressource zugreifen:

[Timer]
OnCalendar=*-*-* 03:00:00
RandomizedDelaySec=900

Dies plant die Aufgabe zwischen 3:00 und 3:15 Uhr, wobei systemd für jeden Boot-Zyklus einen zufälligen Versatz wählt.

Ressourcenkontrolle

Da die Aufgabe als systemd-Service läuft, können Sie Ressourcenlimits anwenden:

[Service]
Type=oneshot
ExecStart=/usr/local/bin/heavy-report.sh
CPUQuota=50%
MemoryMax=512M
IOWeight=50
Nice=15

Cron hat kein Äquivalent dazu — Sie müssten nice, ionice und ulimit-Aufrufe in jedes Skript einfügen.

Fehlerbenachrichtigung

Lösen Sie eine Warnung aus, wenn eine geplante Aufgabe fehlschlägt:

[Unit]
Description=Database backup
OnFailure=notify-admin@%n.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh

Erstellen Sie die Benachrichtigungsvorlage unter /etc/systemd/system/notify-admin@.service:

[Unit]
Description=Send failure alert for %i

[Service]
Type=oneshot
ExecStart=/usr/local/bin/send-alert.sh "Unit %i failed on %H"

Cron-Jobs in systemd-Timer umwandeln

Hier ist ein systematischer Ansatz zur Migration bestehender Cron-Jobs.

Beispiel-Cron-Eintrag:

30 2 * * 1-5 /usr/local/bin/db-backup.sh

Dies führt das Backup um 2:30 Uhr an Werktagen aus. Die entsprechenden systemd-Units:

# /etc/systemd/system/db-backup.service
[Unit]
Description=Database backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/db-backup.sh
# /etc/systemd/system/db-backup.timer
[Unit]
Description=Database backup on weekday nights

[Timer]
OnCalendar=Mon..Fri *-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target

Cron-zu-OnCalendar-Kurzreferenz:

CronOnCalendar
0 * * * * (stündlich)*-*-* *:00:00
*/5 * * * * (alle 5 Min)*-*-* *:00/5:00
0 0 * * 0 (wöchentlich So)Sun *-*-* 00:00:00
0 0 1 * * (monatlich)*-*-01 00:00:00
@rebootVerwenden Sie OnBootSec=0

Nach dem Erstellen der Units:

sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer

# Überprüfen
systemctl list-timers db-backup.timer

# Alten Cron-Eintrag auskommentieren
sudo crontab -e

Überwachung und Debugging von Timern

Alle aktiven Timer auflisten

systemctl list-timers --all

Timer-Logs prüfen

journalctl -u daily-cleanup.service --since today
journalctl -u daily-cleanup.service --since "2025-12-20" --until "2025-12-23"

Einen Timer debuggen, der nicht auslöst

# Timer-Status prüfen
systemctl status daily-cleanup.timer

# Kalenderausdruck überprüfen
systemd-analyze calendar "*-*-* 02:00:00"

# Unit-Datei auf Fehler prüfen
systemd-analyze verify /etc/systemd/system/daily-cleanup.*

# Alle Timer anzeigen, einschließlich inaktiver
systemctl list-timers --all --no-pager

Transiente Timer für einmalige Aufgaben

Müssen Sie etwas in 30 Minuten ausführen, ohne Unit-Dateien zu erstellen?

systemd-run --on-active=30min /usr/local/bin/one-time-task.sh

Oder zu einem bestimmten Zeitpunkt:

systemd-run --on-calendar="2025-12-24 15:00:00" /usr/local/bin/holiday-report.sh

Fehlerbehebung

Timer zeigt “n/a” bei NEXT: Der Timer ist geladen, aber nicht aktiviert. Führen Sie systemctl enable --now <name>.timer aus.

Service läuft, aber Timer löst ihn nicht aus: Stellen Sie sicher, dass die Dateinamen von .timer und .service exakt übereinstimmen. Prüfen Sie mit systemctl cat <name>.timer auf Tippfehler.

“Failed to parse calendar specification”: Ihre OnCalendar-Syntax ist fehlerhaft. Validieren Sie mit systemd-analyze calendar "Ihr Ausdruck".

Timer löst verspätet aus: Der Standard-AccuracySec-Wert beträgt 1 Minute. systemd fasst Aufweckvorgänge zusammen, um Energie zu sparen. Setzen Sie AccuracySec=1s, wenn Sie Präzision benötigen.

Verpasste Ausführungen werden nicht nachgeholt: Sie haben Persistent=true im Abschnitt [Timer] vergessen.

Zusammenfassung

  • systemd-Timer ersetzen Cron durch zwei Unit-Dateien: eine .service (was ausgeführt wird) und eine .timer (wann es ausgeführt wird)
  • OnCalendar verarbeitet uhrzeitbasierte Zeitpläne; OnBootSec und OnUnitActiveSec verarbeiten intervallbasierte Zeitgebung
  • Persistent=true holt verpasste Ausführungen nach Ausfallzeiten nach
  • systemd-analyze calendar ermöglicht die Validierung von Zeitplanausdrücken vor der Bereitstellung
  • Integriertes Logging über journalctl macht benutzerdefinierte Log-Umleitungen überflüssig
  • Ressourcenkontrollen (CPUQuota, MemoryMax) und Fehlerbenachrichtigungen bieten produktionsreife Zuverlässigkeit
  • Jeder Cron-Job kann mit unkomplizierter Syntax-Zuordnung auf einen systemd-Timer migriert werden
  • Verwenden Sie systemd-run für schnelle einmalige geplante Aufgaben ohne Unit-Dateien

Cron-Jobs unter Linux konfigurieren | journalctl: Linux-Systemprotokolle abfragen und analysieren | Linux-Dienste mit systemctl verwalten