Backup and maintenance are the most common reasons people use cron. This episode schedules rsync, restic, and pg_dump correctly, verifies backup results so they don't just run aimlessly, then handles logrotate, tmp cleanup, and package updates that need care.

In episode 9 we built the reliability foundation: lock, retry, idempotency, timeout. Now we apply it to cron's most typical use: backup and maintenance.
Let's set expectations straight first: scheduling a backup is only half the work. A backup that is never verified is not a backup — it's just hope. This episode covers how to schedule backups correctly and at the same time ensure they can actually be restored.
rsync is perfect for backing up files to a local disk or another server — and it's naturally idempotent:
SHELL=/bin/bash
PATH=/usr/local/bin:/usr/bin:/bin
30 2 * * * flock -n /var/lock/rsync.lock rsync -avz --delete /data/ backup@nas:/backup/data/ >> /var/log/backup.log 2>&1--delete makes the target mirror the source (an idempotent operation). Add timeout if the connection often slows down.
restic is a modern backup tool with deduplication, encryption, and snapshots:
30 2 * * * flock -n /var/lock/restic.lock \
restic -r s3:s3.amazonaws.com/bucket backup /data >> /var/log/backup.log 2>&1restic secrets (repo password) should not go in crontab — store them in an env file with 600 permissions (we cover this in episode 14):
RESTIC_REPOSITORY=s3:s3.amazonaws.com/bucket
RESTIC_PASSWORD=very-strong-secretPostgreSQL backups require pg_dump (logical dump) or pg_basebackup (physical). For small-to-medium databases, a logical dump is enough:
30 3 * * * pg_dump -h localhost -U backup_user -Fc mydb > /backup/mydb-$(date +%F).dump 2>> /var/log/backup.logNote the 2>> — stderr is appended to the log while stdout (the dump file) is written with >.
Warning
When automating pg_dump, consider retention: mydb-2026-08-13.dump files pile up forever without cleanup. Add an automatic deletion rule, e.g. find /backup -name "*.dump" -mtime +14 -delete, or use a tool with built-in retention like restic.
Backups need to be proven, not assumed. Three levels of verification:
# Di dalam script backup
if [ $? -ne 0 ] || [ ! -s /backup/mydb.dump ]; then
echo "Backup gagal!" >> /var/log/backup.log
exit 1
fi-s ensures the file is not empty. A non-0 exit code means the dump is incomplete.
restic has a built-in verification command — schedule it periodically:
0 4 * * 0 restic -r s3:s3.amazonaws.com/bucket check --read-data >> /var/log/restic-check.log 2>&1The most important final step: a periodic restore test — restore a backup to a temporary database/file, ideally monthly. If restore is never tested, you won't know the backup works until it's too late.
logrotate runs daily via cron on almost every distro:
cat /etc/cron.d/logrotateConfiguration lives in /etc/logrotate.conf and /etc/logrotate.d/. Make sure your cron job logs have their own rules (for example, in episode 5).
Files in /tmp and caches can fill the disk unnoticed:
0 5 * * * find /tmp -type f -mtime +7 -delete >> /var/log/cleanup.log 2>&1Be careful: don't delete files still in use by other processes — limit by age (-mtime +7) and specific folders.
Automating apt upgrade or dnf update is risky: an update can break dependencies or trigger service restarts. Safer practices:
0 6 * * * apt-get update >> /var/log/apt.log 2>&1Caution
Never schedule apt upgrade -y, dnf upgrade -y, or yum update -y without a staging process. Automated upgrades on a production server are the most common cause of downtime "without a cause" — services restart, the kernel changes, dependencies break, and nobody is watching.
| Type | Example | Frequency | Watch out |
|---|---|---|---|
| File backup | rsync | Daily | --delete, lock |
| Snapshot backup | restic | Daily | Encryption, retention |
| DB backup | pg_dump | Daily | Restore test |
| Verification | restic check | Weekly | --read-data |
| Log rotation | logrotate | Automatic | Per-log rules |
| Cleanup | find /tmp | Daily | Don't delete active files |
| Update | apt-get update | Daily | Index only |
Key takeaways:
In episode 11 we'll cover randomization and avoiding peak load — how sleep $((RANDOM % 300)) spreads load, choosing quiet hours of 02.00-04.00, and preventing many backup hosts from knocking over a server all at once!