Stop reaching for cron: systemd timers in practice
Cron is fine until you need to answer "did it run, and what happened?" Then you're tailing a mail spool or piping output to a logfile you'll forget to rotate. systemd timers give you the scheduling plus the logging, the dependency graph, and a record of every invocation — for free.
The two files
A timer is two units: the thing to run, and when to run it. The service:
# /etc/systemd/system/backup.service
[Unit]
Description=Nightly backup to offsite
[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
Nice=10
IOSchedulingClass=idle
And the timer:
# /etc/systemd/system/backup.timer
[Unit]
Description=Run nightly backup
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=15m
[Install]
WantedBy=timers.target
Persistent=true is the line cron can't match: miss the window because the box was off, and the job runs once at next boot instead of silently skipping. RandomizedDelaySec spreads load if you have a fleet all firing at 03:30.
Then you actually enable it
systemctl daemon-reload
systemctl enable --now backup.timer
systemctl list-timers --all
And when something breaks, the answer is one command, with timestamps, scoped to exactly that job:
journalctl -u backup.service --since yesterday
No mail spool, no redirected logfile, no wondering whether it ran. That's the whole pitch.