๐ŸŽ New User? Get 20% off your first purchase with code NEWUSER20 ยท โšก Instant download ยท ๐Ÿ”’ Secure checkout Register Now โ†’
Menu

Categories

Linux Crontab Backup: Export, Restore, and Diff Your Cron Jobs

Linux Crontab Backup: Export, Restore, and Diff Your Cron Jobs

"crontab -r" is the most dangerous keystroke combination in Unix. One letter from the harmless -l, it deletes your entire crontab with no confirmation. Combine that with the fact that crontabs are routinely lost during server migrations, distro upgrades, and accidental "let me re-run that interactive setup script," and you have a compelling case for backing up scheduled jobs as a routine, automated practice.

Where crontabs actually live

Three locations on most distributions:

  • /var/spool/cron/crontabs/ โ€” per-user crontabs (Debian/Ubuntu).
  • /var/spool/cron/ โ€” per-user crontabs (RHEL family).
  • /etc/crontab and /etc/cron.d/ โ€” system-wide schedules.
  • /etc/cron.{hourly,daily,weekly,monthly}/ โ€” drop-in scripts.

Backing up "the crontab" means capturing all five locations, plus per-user copies for every UID that has one.

The one-line backup

sudo bash -c '
  ts=$(date +%F)
  out=/var/backups/cron/$ts
  mkdir -p "$out"
  cp -a /var/spool/cron "$out/spool"          2>/dev/null
  cp -a /etc/crontab    "$out/etc-crontab"    2>/dev/null
  cp -a /etc/cron.d     "$out/etc-cron.d"     2>/dev/null
  cp -a /etc/cron.hourly /etc/cron.daily \
        /etc/cron.weekly /etc/cron.monthly "$out/" 2>/dev/null
  for u in $(awk -F: "\$3 >= 1000 {print \$1}" /etc/passwd) root; do
    crontab -u "$u" -l 2>/dev/null > "$out/user-$u.cron"
    [ -s "$out/user-$u.cron" ] || rm -f "$out/user-$u.cron"
  done
  tar czf "$out.tar.gz" -C /var/backups/cron "$ts"
  rm -rf "$out"'

Drop the script into /etc/cron.daily/backup-cron and let cron back itself up. Retention via find /var/backups/cron -name '*.tar.gz' -mtime +30 -delete.

Per-user export

crontab -l                                   # show current
crontab -l > ~/cron-backup-$(date +%F).txt   # save
crontab ~/cron-backup-2026-04-15.txt         # restore exact contents

Always pipe crontab -l output to a file before any maintenance โ€” the second of insurance is worth it.

Diff: catching unauthorized changes

A crontab change you did not make is almost always either an attacker establishing persistence or a misbehaving auto-config tool. Detect with diff:

sudo crontab -u root -l > /tmp/cron-now.txt
sudo diff /var/backups/cron/baseline-root.txt /tmp/cron-now.txt

Wrap into a daily check that emails or alerts on any non-empty diff. Persistent attackers love cron because it survives reboot, runs as root, and hides in plain sight.

Restoring after disaster

Two common scenarios:

Scenario A: crontab -r by accident.

crontab ~/cron-backup-2026-04-15.txt
crontab -l                                  # verify

Scenario B: full server rebuild.

tar xzf /backup/cron-2026-04-15.tar.gz -C /tmp
sudo cp /tmp/2026-04-15/etc-crontab /etc/crontab
sudo cp -a /tmp/2026-04-15/etc-cron.d/. /etc/cron.d/
for f in /tmp/2026-04-15/user-*.cron; do
  user=$(basename "$f" .cron); user=${user#user-}
  sudo crontab -u "$user" "$f"
done
sudo systemctl restart cron

Validating cron syntax

Cron silently ignores invalid lines, which is the worst possible failure mode. Validate before deploying:

crontab -T crontab.txt                 # vixie-cron 3.0pl1+
# or:
sudo cat < crontab.txt >> /var/spool/cron/crontabs/testuser
journalctl -u cron --since '5 minutes ago' | grep 'CRON.*ERROR'

For complex schedules, use crontab.guru to translate the expression to English. 0 9 * * 1-5 means "09:00 Monday through Friday" โ€” easy to typo into something else entirely.

Migrating to systemd timers

If you are already operating systemd units, consider converting cron jobs to timers (covered in our systemd-timers article). One automated path: run systemd-analyze calendar 'OnCalendar=...' on each candidate to validate the equivalent expression before cutover.

Best practices

  • Always set MAILTO=ops@example.com at the top of the crontab. Cron emails errors; if you do not collect them, you do not know about failures.
  • Use absolute paths for binaries and data files; cron runs with a near-empty PATH.
  • Redirect both stdout and stderr explicitly: 0 3 * * * /usr/local/bin/job >> /var/log/job.log 2>&1.
  • Avoid clustering many jobs at the top of the hour โ€” stagger them across the hour to reduce contention.
  • Annotate jobs with comments so the next admin understands why each exists.

Common pitfalls

  • crontab -r with no backup; type crontab -i -r instead, which prompts for confirmation.
  • Editing crontab on the wrong host because the prompt did not show the hostname.
  • Forgetting that environment variables in your interactive shell are not present in cron's environment.
  • Putting % in commands without escaping โ€” cron treats % as a newline.

Backing up crontabs is a five-line script and a single daily timer slot. Run it on every server you administer and you will never again hear "the cron job that does X used to exist; nobody knows what it did."

Share this article:
Dargslan Editorial Team (Dargslan)
About the Author

Dargslan Editorial Team (Dargslan)

Collective of Software Developers, System Administrators, DevOps Engineers, and IT Authors

Dargslan is an independent technology publishing collective formed by experienced software developers, system administrators, and IT specialists.

The Dargslan editorial team works collaboratively to create practical, hands-on technology books focused on real-world use cases. Each publication is developed, reviewed, and...

Programming Languages Linux Administration Web Development Cybersecurity Networking

Stay Updated

Subscribe to our newsletter for the latest tutorials, tips, and exclusive offers.