Schedule tasks with cron

2 min read07 November 2026

Cron runs a command on a schedule: backups, certificate renewal, cleanup. It is an old but still available tool, easy to audit and sufficient for most VPS tasks. A badly written crontab fails silently, which is why absolute paths and logs matter.

Understand the syntax

crontab -e opens the current user's crontab. Each active line has five fields then the command:

Text
minute hour day-of-month month day-of-week command

Minutes and hours range from 0 to 59 and 0 to 23. * means "every", */15 means "every fifteen units", 1-5 is a range and 1,15 a list. A daily job at 03:15:

Text
15 3 * * * /usr/local/bin/backup.sh

If both day-of-month and day-of-week are restricted, cron runs the job when either matches. Use @daily, @weekly or @reboot for simple cases. crontab -l prints the crontab; crontab -r deletes it without confirmation, so export it first.

Write a reliable job

Cron starts with a minimal environment: PATH is short and the working directory is the home. Use absolute paths and set the environment at the top of the crontab:

Text
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
MAILTO=""
15 3 * * * flock -n /run/backup.lock /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1
  • flock -n prevents two simultaneous runs if the previous one is still going.
  • >> ... 2>&1 keeps standard output and errors; without redirection, cron tries to send mail and often fails with no mail server.
  • The script needs a shebang and execute permission (chmod 755).
  • Test it as the user who owns the crontab, not as root for convenience.

Files in /etc/cron.d/ add a user field before the command. User crontabs do not.

Check execution

Bash
systemctl status cron
journalctl -u cron --since today
tail -n 20 /var/log/backup.log

To validate a schedule, temporarily use * * * * *, wait one minute, then restore the real timing. Check the timezone with timedatectl: cron follows system time, and a clock change can shift or repeat a job.

Cron or systemd timers?

Criterion cron systemd timer
Simplicity Very simple Requires a unit
Missed run Lost Persistent=true replays it
Logs Manual redirection journalctl -u
Dependencies None After=, Requires=
Precision Minute Second

A timer suits jobs that must survive downtime or depend on another service. Cron remains fine for short, self-contained scripts.

Verify the result

Confirm the job runs at the expected time, the output file grows and the exit code is zero. Add simple supervision: if the backup has not been written for two days, something is broken. An unsupervised scheduled task always fails eventually without anyone noticing.

Advertisement

Was this article helpful?

Read next