EQVPS
DashboardLoslegen

Aufgaben auf einem VPS planen: cron und systemd-Timer

Backups, Aufräumjobs und Skripte nach Zeitplan. Cron in fünf Minuten mit den drei Fallen, die Jobs stillschweigend kaputtmachen, dann systemd-Timer für Logs, Nachholen nach Ausfallzeiten und exaktes Timing. Jedes Verhalten unten wurde auf einem frischen Ubuntu-24.04-Server getestet.

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:

OnCalendarBedeutung
*-*-* 03:30Jeden Tag um 03:30
Mon..Fri *-*-* 09:00Werktags um 09:00
*:0/15Alle 15 Minuten
weeklyMontags um 00:00
*-*-01 04:00Am 1. jedes Monats um 04:00
*-*-* 03:00 Europe/Kyiv03: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

CronSystemd-Timer
Einrichtung1 Zeile2 Dateien
LogsNur wenn du die Ausgabe umleitestjournalctl -u name.service
Verpasster Lauf bei ausgeschaltetem ServerVerlorenLäuft beim Boot mit Persistent=true
Job läuft beim nächsten Termin nochEine zweite Kopie startetÜbersprungen, bis der erste fertig ist
Exakte ZeitAuf die MinuteAuf die Sekunde mit AccuracySec=1s
StatusKeinerlist-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.

FAQ

Warum funktioniert mein Job im Terminal, aber nicht in cron?

Drei übliche Gründe. Cron führt den Job mit sh aus, nicht mit bash, also scheitert reine bash-Syntax. Werkzeuge aus deinem Home-Verzeichnis wie nvm, pipx oder cargo stehen nicht im PATH von cron, also nutze volle Pfade. Und jedes % in der Befehlszeile beendet den Befehl: aus date +%F wurde auf unserem Server date +. Maskiere es als \% oder lagere den Befehl in ein Skript aus.

Wohin geht die Ausgabe von cron?

Standardmäßig per E-Mail. Unser Image hat keinen Mailserver, also schreibt cron 'No MTA installed, discarding output' ins Journal, und die Ausgabe ist weg. Hänge >> /var/log/myjob.log 2>&1 an den Job an oder wechsle zu einem systemd-Timer, dessen Ausgabe automatisch im Journal landet.

Was bringt ein systemd-Timer gegenüber cron?

Logs in journalctl, keine zweite Kopie eines noch laufenden Jobs, Nachholen von Läufen, die bei ausgeschaltetem Server verpasst wurden, mit Persistent=true, und eine Statuszeile mit nächstem und letztem Lauf. Cron gewinnt bei der Kürze: eine Zeile statt zwei Dateien.

Mein Timer hat 18 Sekunden zu spät ausgelöst. Warum?

Standardmäßig bündelt systemd Timer in einem Fenster von einer Minute, um Aufwachvorgänge zu sparen, das ist die Einstellung AccuracySec. Unser Zwei-Minuten-Timer löste um 07:42:18 statt 07:42:00 aus. Mit AccuracySec=1s lief er genau um 07:46:00. Setze sie, wenn die exakte Minute zählt.

Welche Zeitzone nutzen cron und Timer?

Die des Servers, auf unseren Images UTC. Stelle sie einmal mit timedatectl ein, siehe unsere Anleitung zu Hostname und Zeitzone, und cron wie Timer folgen ihr. Timer können auch eine eigene Zone tragen: OnCalendar=*-*-* 03:00 Europe/Kyiv lief in unserem Test um 01:00 UTC.

Kommentare

Noch keine Kommentare. Sei der Erste.

Kommentar hinterlassen

Kommentare werden vor der Anzeige moderiert.