Zum Inhalt springen
CitexNode
Alle Anleitungen

Cronjobs und systemd-Timer

Aufgaben regelmäßig ausführen: crontab-Grundlagen, systemd-Timer und Beispiele.

5 Min. Lesezeit

Für alles, was regelmäßig laufen soll (Backups, Aufräumen, ein Skript jede Stunde), gibt es zwei Wege: cron, den Klassiker, und systemd-Timer, die mehr können und ihre Ausgabe im Journal ablegen.

Gilt für Debian 12 und 13, Ubuntu 22.04 und 24.04, AlmaLinux 9 und Rocky Linux 9. Alle Befehle laufen als root, wenn nichts anderes dasteht.

cron

Installiert?

bash
command -v crontab || echo fehlt

Fehlt es:

bash
apt install -y cron && systemctl enable --now cron       # Debian und Ubuntu
dnf install -y cronie && systemctl enable --now crond    # AlmaLinux und Rocky Linux

Die crontab bearbeiten

bash
crontab -e

Das öffnet die crontab des aktuellen Benutzers im Editor. Jede Zeile ist eine Aufgabe:

text
# Minute  Stunde  Tag  Monat  Wochentag  Befehl
  30      3       *    *      *          /usr/local/bin/backup.sh
FeldWerte
Minute0–59
Stunde0–23
Tag im Monat1–31
Monat1–12
Wochentag0–7 (0 und 7 sind Sonntag)

* heißt „jeder“, */15 „alle 15“, 1-5 „von 1 bis 5“, 1,15 „am 1. und 15.“.

Beispiele

text
# Jeden Tag um 3:30 Uhr
30 3 * * * /usr/local/bin/backup.sh

# Alle 15 Minuten
*/15 * * * * /usr/local/bin/check.sh

# Montag bis Freitag um 8 Uhr
0 8 * * 1-5 /usr/local/bin/bericht.sh

# Am 1. jedes Monats um Mitternacht
0 0 1 * * /usr/local/bin/monatlich.sh

# Nach jedem Neustart
@reboot /usr/local/bin/beim-start.sh

# WordPress-Cron alle 5 Minuten als Webserver-Benutzer (Debian/Ubuntu)
*/5 * * * * sudo -u www-data php /var/www/example.de/wp-cron.php > /dev/null 2>&1

Eine Aufgabe für einen anderen Benutzer legst du mit crontab -u www-data -e an. Dann brauchst du kein sudo -u in der Zeile.

Worauf du achten musst

  • cron kennt kaum Umgebungsvariablen. PATH ist sehr kurz. Schreib Befehle mit vollem Pfad (/usr/bin/php, /usr/local/bin/…), oder setz oben in die crontab PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin.
  • Ausgabe landet sonst im Nichts. cron will sie per Mail schicken; ohne Mailserver geht sie verloren. Leite sie in eine Datei: … >> /var/log/meinjob.log 2>&1.
  • % hat in der crontab eine eigene Bedeutung (Zeilenumbruch). In Befehlen wie date +%F musst du es als \% schreiben, oder du packst den Befehl in ein Skript.
  • Zeitzone. cron nutzt die Zeitzone des Servers. timedatectl zeigt sie, timedatectl set-timezone Europe/Berlin stellt sie um.

Prüfen, ob es geklappt hat

bash
crontab -l

zeigt deine Aufgaben. Ob ein Lauf stattgefunden hat:

bash
journalctl -u cron --since today     # Debian und Ubuntu
journalctl -u crond --since today    # AlmaLinux und Rocky Linux

systemd-Timer

Ein Timer besteht aus zwei Dateien: einem Service, der sagt, was läuft, und einem Timer, der sagt, wann. Vorteile gegenüber cron: Die Ausgabe steht im Journal, verpasste Läufe werden auf Wunsch nachgeholt, und zwei Läufe überlappen sich nie.

Beispiel: Aufräumskript jede Nacht

/etc/systemd/system/aufraeumen.service:

ini
[Unit]
Description=Alte Dateien in /var/tmp/uploads löschen

[Service]
Type=oneshot
ExecStart=/usr/bin/find /var/tmp/uploads -type f -mtime +7 -delete

/etc/systemd/system/aufraeumen.timer:

ini
[Unit]
Description=Jede Nacht aufräumen

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

[Install]
WantedBy=timers.target

Einschalten:

bash
systemctl daemon-reload
systemctl enable --now aufraeumen.timer

Läuft der Dienst als anderer Benutzer, ergänz unter [Service] die Zeile User=www-data.

Zeitangaben für OnCalendar

AngabeBedeutung
hourlyjede volle Stunde
dailyjeden Tag um 0 Uhr
weeklymontags um 0 Uhr
*-*-* 03:30:00jeden Tag um 3:30 Uhr
Mon..Fri 08:00werktags um 8 Uhr
*:0/15alle 15 Minuten
*-*-01 00:00:00am 1. jedes Monats

Ob eine Angabe stimmt und wann sie das nächste Mal greift, zeigt:

bash
systemd-analyze calendar "Mon..Fri 08:00"

Statt einer Uhrzeit geht auch ein Abstand, z. B. OnBootSec=5min und OnUnitActiveSec=1h für „5 Minuten nach dem Start, danach stündlich“.

Prüfen, ob es geklappt hat

bash
systemctl list-timers

zeigt alle Timer mit letztem und nächstem Lauf. Ausgabe und Fehler des letzten Laufs:

bash
journalctl -u aufraeumen.service -n 50 --no-pager

Sofort einmal von Hand ausführen, ohne auf den Timer zu warten:

bash
systemctl start aufraeumen.service

Häufige Fehler

  • Der Befehl klappt im Terminal, aber nicht in cron. Fast immer PATH oder ein relativer Pfad. Volle Pfade nehmen und im Skript mit cd in den richtigen Ordner wechseln.
  • Cron-Skript läuft gar nicht. Ist es ausführbar? chmod +x /usr/local/bin/backup.sh. Hat es eine erste Zeile wie #!/bin/bash?
  • Der Timer steht nicht in list-timers. systemctl daemon-reload vergessen oder den Timer nicht mit enable --now eingeschaltet.
  • Failed to start … Unit … not found. Service und Timer müssen gleich heißen (aufraeumen.service und aufraeumen.timer), sonst braucht der Timer eine Zeile Unit= unter [Timer].
  • Aufgabe läuft zur falschen Zeit. Zeitzone des Servers prüfen (timedatectl).

Wie es weitergeht

Kommst du nicht weiter, schreib uns ein Ticket.