Skip to main content

Cron and Systemd Timers

Automation should be deterministic: same user, same config path, same logs, every run.

Learning Focus

Build schedulers that are boring: same environment, predictable config, and clean failure signals.

Production Requirements​

RequirementWhy
Absolute pathsCron has minimal environment
Explicit config fileAvoid user-context surprises
Log to file (and/or journald)Incident debugging
LockingPrevent overlapping destructive jobs
Exit-code awarenessAlert on failure

Mapping​

Cron Example​

crontab
0 2 * * * /usr/bin/rclone sync /srv/data remote-prod:backup/data --config /etc/rclone/rclone.conf --log-file /var/log/rclone-nightly.log
warning

Cron does not automatically capture stderr/stdout unless you redirect or configure mail. Always log.

Systemd Unit Example​

/etc/systemd/system/rclone-backup.service
[Unit]
Description=Nightly Rclone Backup

[Service]
Type=oneshot
ExecStart=/usr/bin/rclone sync /srv/data remote-prod:backup/data --config /etc/rclone/rclone.conf --log-file /var/log/rclone-nightly.log
/etc/systemd/system/rclone-backup.service
[Unit]
Description=Nightly Rclone Backup

[Service]
Type=oneshot
User=rezriz
Group=rezriz

ExecStart=/usr/bin/flock -n /var/lock/rclone-backup.lock \
/usr/bin/rclone sync /srv/data remote-prod:backup/data \
--config /etc/rclone/rclone.conf \
--log-file /var/log/rclone-nightly.log
/etc/systemd/system/rclone-backup.timer
[Unit]
Description=Run nightly rclone backup

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

[Install]
WantedBy=timers.target

Observability​

Useful commands:

systemctl status rclone-backup.service
journalctl -u rclone-backup.service --since "today"
systemctl list-timers --all | grep rclone

Cron vs Systemd​

TopicCronSystemd timer
LoggingManual redirectionJournald + file logs
Missed-run behaviorNone by defaultPersistent=true catch-up
Dependency controlsLimitedStrong unit ordering and checks
tip

Prefer systemd timers on modern Linux hosts for better observability and restart controls.

Common Pitfalls​

PitfallFailure modeFix
Job runs as root unexpectedlyConfig differs from manual testUse User= and explicit --config
Relative pathsWorks manually, fails in cronUse absolute paths only
No lockingOverlapping syncsWrap in flock
No alertingSilent failureMonitor logs and exit code

What's Next​