CFG-03 · Scheduling

systemd service & timer builder

Describe a command and a schedule, get a working .service + .timer pair and the commands to enable it — the modern, loggable replacement for a crontab entry.

Becomes name.service / name.timer.

backup.service


  

backup.timer


  

Install both files to /etc/systemd/system/, then run systemctl daemon-reload && systemctl enable --now NAME.timer.

Why a timer instead of a cron entry

A systemd timer gets everything a crontab entry doesn't for free: run history and exit status via systemctl status and journalctl -u name.service, automatic dependency ordering (wait for the network, a mount, another service), and Persistent=true catch-up if the machine was off at the scheduled time — a plain cron job that gets skipped during downtime just silently never runs.

The two files always come as a pair

The .timer unit only defines when; it points at a same-named .service unit that defines what runs. Forgetting to enable the timer (and enabling the service instead) is the most common mistake — systemctl enable --now name.timer, not name.service, is what actually schedules it.

Do I enable the .service or the .timer?

The .timer unit — systemctl enable --now name.timer. Enabling the .service instead runs it once immediately and doesn't schedule anything; the timer is what triggers the service repeatedly.

What does Persistent=true actually do?

It records the last trigger time and, if the machine was off or asleep when the timer should have fired, runs the job once as soon as the system is back up. Without it, a missed scheduled run (e.g. a laptop that was shut down overnight) is simply skipped until the next scheduled time.

How do I check a custom OnCalendar expression is valid before using it?

Run systemd-analyze calendar "your expression" — it prints the next several times the expression would fire, or an error if the syntax is invalid, without needing to install the timer first.