Persistent Crontab: How to Make Cron Jobs Survive Reboots and Downtime
Cron is the workhorse scheduler behind countless Linux servers. It runs your nightly backups, log rotations, certificate renewals, and application maintenance scripts without anyone watching. But cron has a reputation for being quietly unreliable: a job vanishes after a reboot, a backup silently stops running, or a task that should have executed during downtime never catches up. Almost always, the root cause is a misunderstanding of how persistent crontab behavior actually works.
This guide explains where crontabs live, why they persist (or appear not to), how to recover missed jobs after downtime, and when to reach for anacron or systemd timers instead of plain cron. By the end, you’ll know how to make scheduled tasks reliable across reboots, users, and outages.
Key Takeaways
• User crontabs are stored in `/var/spool/cron` and persist across reboots automatically — you do not need to “save” them anywhere special.
• A job that “disappears” usually means you edited the wrong user’s crontab, didn’t save the file, or the cron service isn’t enabled to start at boot.
• Standard cron does not run jobs that were missed while the machine was off. Use anacron (for laptops/desktops) or systemd timers with `Persistent=true` to catch up missed runs.
• Always back up with `crontab -l > crontab.backup` before making changes.
• Reliable scheduled tasks depend on an always-on server with a properly enabled cron service.
How Does Crontab Persistence Actually Work?
When you run `crontab -e`, you are not editing a file in your home directory. You are editing a per-user crontab stored in the system spool directory, typically `/var/spool/cron/crontabs/
These files live on disk, which means they survive reboots by default. There is no separate “save and make permanent” step. Once you write and exit the editor, cron validates the syntax and installs the new crontab. The cron daemon re-reads these files on a schedule and after changes, so your jobs continue running indefinitely — as long as the cron service itself starts at boot.
This is the part people miss. The crontab file persisting on disk is necessary but not sufficient. If the cron daemon (`cron` or `crond`) is not enabled to launch at startup, your perfectly valid crontab will sit on disk doing nothing after the next reboot.
System-wide cron jobs live elsewhere and also persist:
- `/etc/crontab` — the main system crontab (includes a username field).
- `/etc/cron.d/` — drop-in files for packages and admins.
- `/etc/cron.hourly/`, `/etc/cron.daily/`, `/etc/cron.weekly/`, `/etc/cron.monthly/` — scripts run on those intervals (often dispatched via anacron on desktop distributions).
Why Does a Cron Job “Disappear” or Stop Running?
A vanishing cron job is rarely cron being mysterious. It’s almost always one of these causes:
- You edited the wrong user’s crontab. Running `crontab -e` as your normal user edits *your* crontab, not root’s. If a job needs root privileges, edit root’s crontab with `sudo crontab -e`. Jobs are scoped per user, so checking the wrong account makes them appear gone.
- The crontab was never saved. If your editor exited without writing the file (or cron rejected the syntax on save), the change was never installed. Cron prints `errors in crontab file, can’t install` when this happens — watch for it.
- The cron service is not running or not enabled. A stopped daemon runs nothing; a daemon that is running now but not *enabled* will not come back after a reboot.
- The job ran but failed silently. A script that depends on `$PATH`, environment variables, or a working directory that exists in your shell but not in cron’s minimal environment will fail. Cron runs with a sparse environment — always use absolute paths.
- You’re on a machine that was powered off. Standard cron does not retroactively run jobs scheduled for a time when the system was down. This is by design, and it’s where anacron and persistent systemd timers come in.
A subtle trap: editing the spool file directly (e.g., `vi /var/spool/cron/crontabs/root`) instead of using `crontab -e` can leave the daemon serving a stale in-memory copy until it next notices the modification time change — and on some hardened setups the file permissions get rewritten, silently disabling the crontab. Always go through `crontab -e`, which signals the daemon correctly and preserves the required `600` ownership.
How Do I Make Sure Jobs Run After Downtime?
This is the real meaning most people have in mind when they search for a “persistent crontab” — not just surviving a reboot, but catching up jobs that were missed while the machine was off or asleep. Plain cron will not do this. You have three practical options.
Option 1: Enable and Verify the Cron Service
Before anything else, make sure cron starts at boot. On most modern systems:
“`bash
sudo systemctl enable –now cron
sudo systemctl enable –now crond “`
The `–now` flag both enables (start at boot) and starts the service immediately. Verify it:
“`bash systemctl status cron # or crond systemctl is-enabled cron # should print “enabled” “`
On an always-on server, this alone makes your crontab reliable across reboots. The service comes back, re-reads `/var/spool/cron`, and resumes the schedule.
Option 2: Use anacron for Machines That Aren’t Always On
anacron is designed for systems that are *not* running 24/7 — laptops, workstations, or intermittently powered servers. Instead of running jobs at an exact time, anacron tracks when each job *last ran* and executes it if the required interval has elapsed since then. If your machine was off at 2 a.m., anacron runs the daily job shortly after the next boot.
anacron works in days (or longer), not minutes, so it’s for daily/weekly/monthly tasks — not jobs that need to fire every five minutes. Its configuration lives in `/etc/anacrontab`:
“`
1 5 cron.daily run-parts /etc/cron.daily 7 10 cron.weekly run-parts /etc/cron.weekly @monthly 15 cron.monthly run-parts /etc/cron.monthly “`
anacron records timestamps in `/var/spool/anacron/`, which is how it knows what to catch up.
Option 3: Use systemd Timers with Persistent=true
systemd timers are the modern alternative to cron on systemd-based distributions. The key feature for our purpose is `Persistent=true` in the timer’s `[Timer]` section. With it set, if a scheduled run was missed because the system was off, systemd triggers the job once immediately after boot.
A timer is two units — a `.service` (what to run) and a `.timer` (when to run it):
“`ini
[Unit] Description=Daily backup timer
[Timer] OnCalendar=*-*-* 02:00:00 Persistent=true
[Install] WantedBy=timers.target “`
Enable it like any unit:
“`bash sudo systemctl enable –now backup.timer systemctl list-timers # shows next and last run times “`
`Persistent=true` is the systemd equivalent of anacron’s catch-up behavior, but with the full power of journald logging, dependency ordering, and resource controls.
Crontab vs Anacron vs systemd Timers: Which Should You Use?
Each tool fits a different reliability profile. Use this comparison to choose.
| Feature | crontab (cron) | anacron | systemd timers |
|---|---|---|---|
| Runs at exact times | Yes (to the minute) | No (daily granularity) | Yes (to the second) |
| Catches up missed jobs after downtime | No | Yes | Yes (with `Persistent=true`) |
| Minimum interval | 1 minute | 1 day | 1 second |
| Per-user scheduling | Yes (`crontab -e`) | No (system-wide) | Yes (user timers) |
| Best for | Always-on servers, frequent jobs | Laptops/desktops, daily+ jobs | Modern servers, complex dependencies |
| Logging | syslog / cron log | syslog | journald (`journalctl -u`) |
| Dependency handling | None | None | Full (units, ordering) |
| Configuration | `crontab`, `/etc/cron.d` | `/etc/anacrontab` | `.timer` + `.service` units |
Rule of thumb: On a 24/7 server, plain cron is fine and simplest. If the machine sleeps or powers off, choose anacron (simple, daily+) or systemd timers with `Persistent=true` (precise, feature-rich).
What Is the Basic Cron Syntax?
A crontab line has five time-and-date fields followed by the command to run. Each field accepts a number, a list (`1,15`), a range (`1-5`), a step (`*/10`), or `*` for “every.”
| Field | Allowed values | Meaning |
|---|---|---|
| Minute | 0–59 | Minute of the hour |
| Hour | 0–23 | Hour (24-hour clock) |
| Day of month | 1–31 | Calendar day |
| Month | 1–12 (or Jan–Dec) | Month |
| Day of week | 0–7 (0 and 7 = Sunday) | Weekday |
Examples:
“`bash
30 2 * * * /usr/local/bin/backup.sh
*/15 * * * * /usr/local/bin/check-queue.sh
0 6 * * 1-5 /usr/local/bin/weekday-report.sh
@reboot /usr/local/bin/startup.sh “`
The `@reboot` shortcut, along with `@daily`, `@weekly`, `@monthly`, and `@yearly`, replaces the five fields for common schedules. Note `@reboot` runs when *cron starts*, not on a fixed clock time.
How Do I Back Up and Restore a Crontab?
Because crontabs are easy to overwrite or lose, back them up before editing. The whole crontab is just text:
“`bash
crontab -l > ~/crontab.backup
sudo crontab -l > /root/crontab.backup
crontab ~/crontab.backup “`
For broader coverage, archive the system spool and config too:
“`bash sudo tar czf cron-backup.tar.gz /var/spool/cron /etc/crontab /etc/cron.d /etc/cron.* “`
Store these backups off the server as part of your regular backup routine so a failed disk doesn’t take your schedule with it.
How Do I Debug and Log Cron Jobs?
When a job misbehaves, cron’s silence is the enemy. Build in visibility:
- Capture output explicitly. Cron emails output to the local user by default, which often goes unread. Redirect instead:
“`bash 0 2 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 “` The `2>&1` sends both standard output and errors to the same log.
- Check the cron log. On Debian/Ubuntu, look in `/var/log/syslog` (filter for `CRON`); on RHEL-based systems, check `/var/log/cron`. For systemd timers, use `journalctl -u backup.service`.
- Use absolute paths. Cron’s `$PATH` is minimal. Reference binaries and files by full path, or set `PATH=` at the top of the crontab.
- Set the shell and environment. Add `SHELL=/bin/bash` and any required variables at the top of the crontab; cron does not source your `.bashrc`.
- Test the command manually in a clean shell (`env -i /bin/bash –noprofile –norc`) to reproduce cron’s stripped environment.
Run Reliable Scheduled Tasks on DarazHost Infrastructure
Persistent cron jobs depend on one thing above all: an always-on server with a properly running, enabled cron service. That’s exactly what DarazHost is built to provide.
- VPS and dedicated servers with full root access. Enable `cron`/`crond`, install anacron, and configure systemd timers with `Persistent=true` — you control the scheduler end to end, ideal for backups, custom scripts, and the WHMCS cron that billing automation relies on.
- Reliable, always-on infrastructure. Our servers stay up so your scheduled jobs actually fire on time, reboot after reboot — the foundation persistent crontab behavior requires.
- cPanel cron job manager on shared hosting. Prefer not to touch the command line? Shared plans include a point-and-click cron job manager in cPanel to schedule tasks without editing spool files.
- 24/7 expert support. If a job isn’t firing or a service won’t enable at boot, our team helps you diagnose it any time.
Whether you need root-level scheduling on a VPS or a simple cPanel cron entry, DarazHost gives your automated tasks a dependable home.
Frequently Asked Questions
Do crontab entries survive a reboot? Yes. User crontabs are stored on disk in `/var/spool/cron` and persist automatically across reboots. The only requirement is that the cron service (`cron` or `crond`) is enabled to start at boot — otherwise the jobs sit on disk but never run. Run `systemctl enable –now cron` to be sure.
Why did my cron job stop working after I rebooted? The most common reasons are that the cron service was running but not enabled (so it didn’t restart at boot), or you edited a different user’s crontab than the one being checked. Verify with `systemctl is-enabled cron` and confirm you’re inspecting the correct user with `crontab -l` (or `sudo crontab -l` for root).
How do I run a cron job that was missed while the server was off? Standard cron will not catch up missed jobs. Use anacron for daily-or-longer tasks on machines that aren’t always on, or a systemd timer with `Persistent=true`, which runs a missed job once immediately after the next boot.
Where are crontab files actually stored? Per-user crontabs live in `/var/spool/cron/crontabs/` (Debian/Ubuntu) or `/var/spool/cron/` (RHEL-based). System jobs live in `/etc/crontab`, `/etc/cron.d/`, and the `/etc/cron.*` directories. Always edit user crontabs with `crontab -e` rather than touching the spool files directly.
Should I use cron or systemd timers? On an always-on server, plain cron is simple and reliable. Choose systemd timers when you need missed-run catch-up (`Persistent=true`), second-level precision, dependency ordering, or unified `journalctl` logging. They can coexist on the same system.