Ein Server verdient sein Geld, indem er arbeitet, während du schläfst: Backups, Log-Rotation, Zertifikatserneuerung, ein Bericht um neun. Linux hat dafür zwei Planer. Cron ist vierzig Jahre alt und braucht eine Zeile. Systemd-Timer brauchen zwei kleine Dateien und liefern dafür Logs, Nachholen nach Ausfällen und exaktes Timing. Diese Anleitung behandelt beide unter Ubuntu 24.04, jedes Verhalten geprüft auf einem frischen Server aus unserem Image, einschließlich der drei Fehler, durch die ein cron-Job ohne ein Wort scheitert.
Du brauchst einen Benutzer mit sudo; die Ubuntu-Einrichtungsanleitung legt einen an.
1. Cron in fünf Minuten
Cron ist auf unseren Ubuntu- und Debian-Images installiert und läuft. Jeder Benutzer hat eine Job-Tabelle; deine bearbeitest du mit:
crontab -e
Jede Zeile besteht aus fünf Zeitfeldern und einem Befehl:
# min hour day month weekday command
30 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
*/5 * * * * /usr/local/bin/check.sh
0 9 * * 1-5 /usr/local/bin/report.sh
@reboot /usr/local/bin/start-tunnel.sh
Also: jede Nacht um 03:30, alle 5 Minuten, werktags um 09:00 und einmal nach jedem Boot. */5 heißt jeder fünfte Wert, 1-5 ein Bereich, 1,15 eine Liste. Es gilt die Zeitzone des Servers, auf unseren Images UTC; stelle deine einmal mit der Anleitung zu Hostname und Zeitzone ein, und cron folgt.
Was gelaufen ist, zeigt journalctl -u cron. Jeder Lauf protokolliert Benutzer und Befehl, und genau dort zeigen sich die drei Fallen.
Falle 1: die Ausgabe verschwindet. Cron mailt die Ausgabe eines Jobs an den Benutzer. Unser Image hat keinen Mailserver, also stand im Journal (CRON) info (No MTA installed, discarding output), und die Ausgabe war weg. Leite sie selbst um, wie im ersten Beispiel mit >> /var/log/backup.log 2>&1.
Falle 2: das Prozentzeichen. In einer crontab beendet % den Befehl und macht den Rest zur Standardeingabe. Wir planten date +%F > /tmp/today. Das Journal zeigt, was cron wirklich ausführte: CMD (date +). Es wurde keine Datei geschrieben, und kein Fehler erreichte uns. Schreibe \% oder lege den Befehl in ein Skript und plane das Skript.
Falle 3: eine andere Umgebung. Cron führt Jobs mit /bin/sh aus, nicht mit bash, in deinem Home-Verzeichnis und mit knapper Umgebung. Unter Ubuntu 24.04 war der PATH besser als sein Ruf, der volle Systempfad inklusive /usr/local/bin und /snap/bin, für root und für normale Benutzer. Was weiterhin fehlt, ist alles unter deinem Home: ~/.local/bin, node aus nvm, pipx, cargo. Nutze volle Pfade im Job oder beginne die Zeile mit . $HOME/.profile;.
Jobs, die zum System statt zu einem Benutzer gehören, kommen als Datei nach /etc/cron.d/, mit einem zusätzlichen Feld, dem Benutzer:
30 3 * * * root /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
Ubuntu führt außerdem alles in /etc/cron.hourly, cron.daily, cron.weekly und cron.monthly aus, um 17 Minuten nach jeder Stunde, um 06:25, sonntags um 06:47 und am 1. um 06:52. Lege dort ein ausführbares Skript ab, und es läuft mit den anderen.
2. Systemd-Timer
Ein Timer besteht aus zwei Units: einem Service, der die Arbeit macht, und einem Timer, der sagt wann. Erstelle zuerst das Skript, dann die Units.
sudo nano /usr/local/bin/backup.sh
sudo chmod +x /usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
sudo nano /etc/systemd/system/backup.timer
[Unit]
Description=Run the backup every night at 03:30
[Timer]
OnCalendar=*-*-* 03:30
Persistent=true
AccuracySec=1m
[Install]
WantedBy=timers.target
Aktiviere den Timer, nicht den Service:
sudo systemctl daemon-reload
sudo systemctl enable --now backup.timer
systemctl list-timers backup.timer
list-timers zeigt den nächsten Lauf, die Zeit bis dahin und den letzten Lauf. Logs brauchen keine Einrichtung: journalctl -u backup.service enthält jeden Start, jedes Ende und jede Ausgabezeile mit Zeitstempel. Um den Job sofort laufen zu lassen, sudo systemctl start backup.service; so testest du auch das Skript, bevor du dem Zeitplan vertraust.
Kalender-Syntax. OnCalendar liest sich als Wochentag Jahr-Monat-Tag Stunde:Minute:Sekunde, mit * für beliebig. Teste einen Ausdruck, bevor du ihn nutzt:
systemd-analyze calendar "Mon..Fri *-*-* 03:00" --iterations 2
Es gibt die normalisierte Form und die nächsten Termine aus. Einige Ausdrücke, die wir geprüft haben:
| OnCalendar | Bedeutung |
|---|---|
*-*-* 03:30 | Jeden Tag um 03:30 |
Mon..Fri *-*-* 09:00 | Werktags um 09:00 |
*:0/15 | Alle 15 Minuten |
weekly | Montags um 00:00 |
*-*-01 04:00 | Am 1. jedes Monats um 04:00 |
*-*-* 03:00 Europe/Kyiv | 03:00 Kyjiwer Zeit; lief bei uns um 01:00 UTC |
Die drei Einstellungen, die du kennen solltest. Persistent=true speichert den letzten Lauf auf der Platte und holt einen Lauf nach, der verpasst wurde, während der Server aus oder der Timer gestoppt war. Wir stoppten unseren Zwei-Minuten-Timer, warteten über einen geplanten Lauf hinaus und starteten ihn wieder: der verpasste Lauf startete in derselben Sekunde. Ohne Persistent wartet er einfach auf den nächsten Termin.
AccuracySec ist die Überraschung. Systemd bündelt Timer standardmäßig in einem Fenster von einer Minute, um Aufwachvorgänge zu sparen, daher kam unser erster Lauf um 07:42:18, nicht um 07:42:00. Mit AccuracySec=1s landeten die nächsten Läufe sekundengenau auf 07:46:00 und 07:48:00. Setze es, wenn die Minute zählt; für ein nächtliches Backup lass den Standard.
RandomizedDelaySec=10m macht absichtlich das Gegenteil: es verteilt den Start über ein Fenster, damit nicht zehn Server in derselben Sekunde denselben Backup-Speicher treffen.
Für einen einmaligen Job brauchst du gar keine Dateien:
sudo systemd-run --on-active=30m --unit=cleanup-once /usr/local/bin/cleanup.sh
Das erzeugt einen transienten Timer, der einmal auslöst und verschwindet; bis dahin zeigt ihn systemctl list-timers.
3. Was wann
| Cron | Systemd-Timer | |
|---|---|---|
| Einrichtung | 1 Zeile | 2 Dateien |
| Logs | Nur wenn du die Ausgabe umleitest | journalctl -u name.service |
| Verpasster Lauf bei ausgeschaltetem Server | Verloren | Läuft beim Boot mit Persistent=true |
| Job läuft beim nächsten Termin noch | Eine zweite Kopie startet | Übersprungen, bis der erste fertig ist |
| Exakte Zeit | Auf die Minute | Auf die Sekunde mit AccuracySec=1s |
| Status | Keiner | list-timers, systemctl status |
Nimm cron für eine schnelle Zeile, die du auch in einem Jahr noch erkennst. Nimm einen Timer für alles, dessen Ausfall du sehen musst, das sich nicht überschneiden darf oder das nach einem verpassten Reboot trotzdem laufen muss: Backups, Zertifikatserneuerung, Datenbank-Aufräumen. Wenn sich ein cron-Job überschneiden kann, umhülle ihn: flock -n /tmp/backup.lock /usr/local/bin/backup.sh, und die zweite Kopie beendet sich sofort.
Beide Planer starten einen Job und hören dann auf. Für ein Programm, das rund um die Uhr laufen und nach einem Absturz wiederkommen soll, brauchst du einen Dienst statt eines Zeitplans; siehe wie du einen systemd-Dienst erstellst und für Windows wie du ein Skript 24/7 auf Windows Server betreibst. Ein guter erster Timer ist der aus unserer restic-Backup-Anleitung; automatische Sicherheitsupdates sind ein Timer, den Ubuntu schon mitbringt, apt-daily-upgrade.timer, einer der 17, die auf einem frischen Server laufen.
Kommentare
Noch keine Kommentare. Sei der Erste.