Linux VPS

Schedule jobs with systemd timers instead of cron

Create a systemd service and timer pair, use OnCalendar schedules, catch up on missed runs with Persistent, view logs in journalctl and list upcoming runs.

IntermediateLinux VPS3 min read

Systemd timers are the modern alternative to cron on Linux. Each job is a normal systemd service, so you get logging in journalctl, resource limits, dependencies and the ability to catch up on runs missed while the server was off. This guide converts a typical cron job into a timer.

Before you start

  • Root access to any systemd-based distro (Ubuntu, Debian, AlmaLinux, Rocky).
  • A script that works when run by hand, e.g. /usr/local/bin/backup.sh (executable, with a shebang line).

How timers work

You create two unit files with the same name:

  • backup.service: what to run.
  • backup.timer: when to run it.

You enable the timer, not the service; the timer starts the service at the scheduled times.

Create the service

Create /etc/systemd/system/backup.service:

[Unit]
Description=Nightly backup

[Service]
Type=oneshot
ExecStart=/usr/local/bin/backup.sh
User=root
Nice=10
IOSchedulingClass=idle

Type=oneshot suits scripts that run and exit. Nice and IOSchedulingClass keep the job from slowing down the website.

Create the timer

Create /etc/systemd/system/backup.timer:

[Unit]
Description=Run backup daily at 02:30

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true
RandomizedDelaySec=10m

[Install]
WantedBy=timers.target
  • Persistent=true: if the server was down at 02:30, run the job as soon as it boots.
  • RandomizedDelaySec: spreads start times so many servers do not hit a backup target at once.

Enable and start the timer

systemctl daemon-reload && systemctl enable --now backup.timer

Run the job immediately to test it:

systemctl start backup.service

OnCalendar examples

ScheduleOnCalendar value
Every 15 minutes*:0/15
Hourlyhourly
Daily at midnightdaily
Mondays at 06:00Mon *-*-* 06:00:00
Weekdays at 09:00Mon..Fri 09:00
First of the month*-*-01 03:00:00

Check how systemd interprets an expression and when it next fires:

systemd-analyze calendar 'Mon..Fri 09:00'

For intervals relative to boot or last run, use OnBootSec=5min and OnUnitActiveSec=1h instead of OnCalendar.

Monitor timers and logs

  • List all timers with last and next run: systemctl list-timers
  • View the job's output: journalctl -u backup.service (add -f to follow, --since today to filter)
  • Check the last result: systemctl status backup.service

For alerts on failure, add OnFailure=notify-failure@%n.service to the service's [Unit] section, pointing to a small service that sends an email or webhook.

Cron vs systemd timers

cronsystemd timers
SetupOne lineTwo small files
LogsManual redirectsAutomatic in journalctl
Missed runsSkippedCaught up with Persistent
Overlap protectionNeeds flockBuilt in: a running service is not started twice
Resource limitsNoCPU, memory, I/O limits

Troubleshooting

  • Timer is active but the job never runs: check systemctl list-timers for the next run and test the calendar expression.
  • Unit not found: run systemctl daemon-reload after creating or editing unit files.
  • Job fails with status=203/EXEC: the script path is wrong, not executable, or missing its shebang.
  • Environment variables missing: add Environment= or EnvironmentFile= lines to the service.

Systemd timers FAQ

Can normal users create timers?

Yes, as user units in ~/.config/systemd/user/, managed with systemctl --user. Run loginctl enable-linger user so they run while the user is logged out.

Should I replace all cron jobs?

Not necessarily. Cron is fine for simple tasks; timers are worth it for jobs where logging, catch-up or limits matter.

Are timers available on cPanel hosting?

No, shared hosting accounts use cron jobs in cPanel. Timers need root access on your own server.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.