cron runs jobs at exact times. If the machine is off (or rebooting) at that moment, the job simply doesn’t run. anacron solves this for periodic jobs: it remembers when each job last ran, and if a day, week or month has passed, it runs the job after the system comes back. It’s mainly used for the system’s daily, weekly and monthly maintenance jobs.
cron vs anacron
| cron | anacron | |
|---|---|---|
| Schedule precision | Exact minute | Daily, weekly, monthly (or every N days) |
| Missed runs | Skipped | Run later, after a delay |
| Runs as | Any user | root (system jobs) |
| Typical use | Servers that are always on, precise timing | Laptops, desktops, servers that may be off; system maintenance |
On most Debian and Ubuntu systems, both are present: cron triggers anacron, which runs /etc/cron.daily, /etc/cron.weekly and /etc/cron.monthly.
How it works on Debian/Ubuntu
cat /etc/anacrontab
ls /etc/cron.daily /etc/cron.weekly /etc/cron.monthly
ls /var/spool/anacron/ # timestamps of the last runs
/etc/anacrontab:
SHELL=/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# period delay job-identifier command
1 5 cron.daily run-parts --report /etc/cron.daily
7 10 cron.weekly run-parts --report /etc/cron.weekly
@monthly 15 cron.monthly run-parts --report /etc/cron.monthly
| Field | Meaning |
|---|---|
| period | Days between runs (1, 7), or @daily, @weekly, @monthly |
| delay | Minutes to wait after anacron starts, so jobs don’t all run at boot |
| job-identifier | Name used for the timestamp file in /var/spool/anacron/ |
| command | What to run |
START_HOURS_RANGE=3-22 limits when jobs may start, and RANDOM_DELAY=45 adds up to 45 random minutes (RHEL-family defaults include these).
Add your own job
Easiest: drop an executable script into one of the directories:
sudo install -m 755 /dev/stdin /etc/cron.daily/backup-config <<'EOF'
#!/bin/sh
tar czf /var/backups/etc-$(date +%F).tgz /etc 2>/dev/null
find /var/backups -name 'etc-*.tgz' -mtime +14 -delete
EOF
run-parts only runs files whose names contain letters, digits, underscores and hyphens: no dots (so backup.sh is silently skipped). Test which scripts would run:
run-parts --test /etc/cron.daily
Or add a line to /etc/anacrontab:
3 20 cleanup-uploads /usr/local/bin/cleanup-uploads.sh
(Runs every 3 days, 20 minutes after anacron starts.)
Test and force runs
sudo anacron -T # check anacrontab syntax
sudo anacron -f -n -d # force all jobs now, no delay, in the foreground
sudo anacron -f -n -d cron.daily # just one job
Timestamps are updated after each run. Delete a timestamp file to make a job due again.
On always-on servers
On a VPS that runs 24/7, missed runs only happen during reboots and maintenance, so plain cron is usually fine. anacron still matters for the system’s own maintenance scripts (log rotation, apt cleanups, man-db), which is why it’s installed by default.
For your own scheduled tasks, systemd timers with Persistent=true provide the same catch-up behaviour, plus better logging and dependencies. See systemd timers.
[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=30m
Troubleshooting
- A script in cron.daily never runs: check its name (no dots), that it’s executable, and
run-parts --test. - Jobs run at odd times: the delay and random delay settings, or
START_HOURS_RANGE, shift them. That’s intended. - Nothing runs at all: on systemd systems, anacron may be started by a timer (
systemctl list-timers | grep anacron) rather than by cron. Check that it’s enabled.
Quick reference
| Task | Command / file |
|---|---|
| Config | /etc/anacrontab |
| Daily/weekly/monthly scripts | /etc/cron.{daily,weekly,monthly}/ |
| Last runs | /var/spool/anacron/ |
| Which scripts run | run-parts --test /etc/cron.daily |
| Force now | sudo anacron -f -n -d |
Related: crontab guide and cron job not running.