Linux: Systemd Timers — A Safer, Inspectable Alternative to Cron

Colored-pencil illustration of a dark server console with green terminal lines for a systemd timer.

Systemd timers schedule work by activating a service unit. On Linux systems that use systemd, this keeps the schedule, the command, and the execution result in inspectable units rather than a single crontab line. The approach is particularly useful for backups, reports, cleanup jobs, and maintenance tasks that should leave an auditable trail.

The Timer and the Service Are Separate

A .timer unit answers when work should run. A matching .service unit answers what should run. Naming both files inventory-report.timer and inventory-report.service gives the timer a natural target. The systemd.timer reference documents calendar schedules, boot-relative schedules, persistence, accuracy, and the unit activation model.

# /etc/systemd/system/inventory-report.service
[Unit]
Description=Write a daily inventory report

[Service]
Type=oneshot
ExecStart=/usr/local/sbin/inventory-report
# /etc/systemd/system/inventory-report.timer
[Unit]
Description=Run the inventory report every day

[Timer]
OnCalendar=*-*-* 02:15:00
Persistent=true
Unit=inventory-report.service

[Install]
WantedBy=timers.target

Type=oneshot is appropriate when the command completes and exits. OnCalendar= describes wall-clock time; Persistent=true asks systemd to run a missed calendar event after the machine returns, rather than silently skipping it. That is a meaningful difference for routine jobs on laptops or intermittently powered lab machines.

Install, Enable, and Inspect

After saving both unit files, reload the manager, enable the timer, and inspect the next scheduled event. Do not enable the service directly: the timer is the unit that should be enabled.

sudo systemctl daemon-reload
sudo systemctl enable --now inventory-report.timer
systemctl list-timers --all
systemctl status inventory-report.timer

The timer can be tested without waiting for 02:15. Starting it manually activates the matching service, and the execution record appears in the journal.

sudo systemctl start inventory-report.service
systemctl status inventory-report.service
journalctl -u inventory-report.service --since today

This pairing is also easier to reason about than a long shell fragment in a scheduler. The service can set an explicit user, working directory, environment, restart policy, and hardening controls. The timer can be listed with every other scheduled systemd job. For broader context on why Linux systems reach from servers to embedded and scientific environments, see Linux at 35; for a production example, see how CERN moved accelerator-control systems to Debian 13.

Choose the Right Schedule

  • Use OnCalendar=Mon..Fri 08:30 for a weekday wall-clock schedule.
  • Use OnBootSec=10min for work that begins a fixed interval after boot.
  • Use OnUnitActiveSec=1h when the next run should be measured from the previous activation.
  • Use systemd-analyze calendar 'Mon..Fri 08:30' to validate a calendar expression before enabling it.

Calendar and elapsed-time schedules solve different problems. A calendar schedule is appropriate for a report expected at a recognizable time. An elapsed schedule is useful when a task should run at an interval even if the start time changes. The Red Hat explanation of OnCalendar is a useful second reference for interpreting calendar expressions.

Guardrails for Production Jobs

  • Call programs by absolute path in ExecStart=.
  • Keep the service small; place substantial logic in a version-controlled script.
  • Run a maintenance command manually before scheduling it.
  • Use a dedicated non-root account whenever privileges are not required.
  • Review journalctl -u name.service after the first automatic run.
  • Disable the timer before editing a job that could affect production data.

A Practical Starting Point

Create a harmless job first: write the current date to a file in /tmp. Confirm that the timer appears in list-timers, start the service manually, inspect its journal, and only then replace the test command with a real task. This preserves the visibility expected from a modern Linux service manager while avoiding a blind migration of every cron job.


BitcoinVersus.Tech

Editor’s Note: This evergreen guide is educational. Test scheduling changes on a non-production system before use.

Support/Donation: 3C9o19EH5HSiwEPyCTmEKzxhNCbo2X6TTb

Disclaimer: Technical information is provided as-is without warranty. Commands can change system state; review documentation and local policy before running them.

Leave a comment