How to schedule tasks with cron on Linux
Backups, cleanups, restarts, reports: a server accumulates jobs that should run by themselves at set times. On Linux, the classic tool is cron. It is installed everywhere, uses almost no resources and does exactly one thing: run commands on a schedule. Its only real difficulty is the schedule syntax, and a few traps that make jobs quietly not run.
Editing your crontab
Each user has a personal table of jobs, called a crontab. Edit yours with:
crontab -e
The first time, it asks which editor to use. Choose the one you are comfortable with. Save and quit, and cron reads the new schedule automatically. See your current jobs with crontab -l.
To run a job as root, use sudo crontab -e. Prefer a normal user when the job does not need extra power.
The schedule format
Each line has five time fields, then the command:
minute hour day-of-month month day-of-week command
| Field | Allowed values |
|---|---|
| Minute | 0 to 59 |
| Hour | 0 to 23 |
| Day of month | 1 to 31 |
| Month | 1 to 12 |
| Day of week | 0 to 7, where 0 and 7 are Sunday |
A * means "every". Examples:
| Schedule | Meaning |
|---|---|
0 4 * * * | Every day at 04:00 |
*/15 * * * * | Every 15 minutes |
30 2 * * 0 | Sundays at 02:30 |
0 0 1 * * | At midnight on the first of each month |
0 9-17 * * 1-5 | On the hour, from 9 to 17, Monday to Friday |
@reboot | Once, when the machine starts |
There are also shortcuts like @daily and @hourly. A small website that explains a schedule in plain words is handy to check yours.
A complete example
A nightly backup of a folder, with its output logged:
0 3 * * * /usr/bin/rsync -a /var/www/ /backup/www/ >> /var/log/backup.log 2>&1
Several details in this line matter, and explain most failures.
The traps
Use full paths. Cron runs with a tiny environment, so the PATH is minimal. A command that works in your terminal can fail in cron because it is not found. Give the full path to programs and files, such as /usr/bin/rsync. Find a program's path with which rsync.
Capture the output. By default, cron tries to email any output, which usually goes nowhere. Redirect it to a file, as in >> /var/log/backup.log 2>&1. This writes both normal output and errors to the log, and it is the first place to look when a job misbehaves.
Mind the time zone. Cron uses the server's time zone, which is often UTC. Check it with timedatectl. If you want 04:00 in your own zone, convert it.
Percent signs. In a crontab, % has a special meaning and must be escaped as \%. This catches people who put date +%Y-%m-%d in a command.
Permissions. The job runs as the user who owns the crontab. It needs permission for every file it touches, and it must be able to run the script, so make scripts executable with chmod +x.
Overlapping runs. If a job takes longer than its interval, a second copy starts while the first is still running. Use flock to make a job skip if one is already running:
*/10 * * * * /usr/bin/flock -n /tmp/myjob.lock /home/alex/myjob.sh
Testing a job
Before trusting a schedule, run the command by hand exactly as written, as the same user. Then temporarily set it to run every minute, watch the log, and set it to the real schedule once it works. Check that cron is running with systemctl status cron.
To see whether cron attempted a job, look in the system log:
sudo journalctl -u cron --since "1 hour ago"
How to read your server logs has general tips on reading logs.
Common uses
- Backups, as in How to back up your VPS with rsync.
- Database dumps, as in How to install and secure MariaDB on Ubuntu.
- Clearing old logs and temporary files, to keep disks from filling. See Fixing "No space left on device".
- Restarting a service nightly, which suits some game servers.
- Certificate renewal. Certbot normally sets this up itself.
Game and bot servers on a panel use the panel's own scheduler instead. See Schedule automatic restarts and backups.
Alternatives
Modern systems have systemd timers, which do the same job with better logging and clearer dependencies. They are worth learning for important tasks, and How to run a service with systemd is a good first step. For simple jobs, cron is still the quickest.
Checklist
- Test the command by hand.
- Use full paths.
- Redirect output to a log.
- Check the time zone.
- Escape any percent signs.
- Guard against overlap.
- Confirm it ran, by reading the log.
Still stuck? Open a ticket on Discord - run /ticket in any channel, pick a department, and include your Server ID or Invoice ID so we can jump straight in.