Schedule tasks with cron
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:
minute hour day-of-month month day-of-week commandMinutes 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:
15 3 * * * /usr/local/bin/backup.shIf 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:
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>&1flock -nprevents two simultaneous runs if the previous one is still going.>> ... 2>&1keeps 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
systemctl status cron
journalctl -u cron --since today
tail -n 20 /var/log/backup.logTo 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
- Manage services with systemdEssential systemctl commands, a custom unit for an application and reading its logs.
- Read logs with journalctlFilter by service and date, find a boot error and control journal disk usage.
- Change the SSH port safelyMove SSH to another port by opening the firewall first and testing from a second session.