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