Linux Basic — Automated Backup Script

1 minute read

Automated Backup Script

A real-world backup script that runs daily from cron, keeps the last 7 days, and logs everything.


Full Script

#!/usr/bin/env bash
set -euo pipefail

PATH=/usr/local/bin:/usr/bin:/bin
BACKUP_SRC="/var/www"
BACKUP_DST="/mnt/backups"
RETENTION_DAYS=7
LOGFILE="/var/log/backup.log"
LOCKFILE="/var/run/backup.lock"

log() { echo "$(date '+%F %T') $*" | tee -a "$LOGFILE"; }
die() { log "ERROR: $*"; exit 1; }

# lock
exec 9>"$LOCKFILE"
flock -n 9 || die "backup already running"
trap 'rm -f "$LOCKFILE"' EXIT

log "starting backup"

# create dated backup dir
today=$(date +%F)
target="$BACKUP_DST/$today"
[[ -d "$target" ]] && die "backup for $today already exists"

mkdir -p "$target" || die "failed to create $target"

# rsync with hard-link to yesterday (incremental)
yesterday=$(date -d '1 day ago' +%F 2>/dev/null || date -v -1d +%F)
link_dest_opt=""
if [[ -d "$BACKUP_DST/$yesterday" ]]; then
    link_dest_opt="--link-dest=$BACKUP_DST/$yesterday"
fi

log "running rsync"
rsync -a --delete $link_dest_opt "$BACKUP_SRC/" "$target/" \
    || die "rsync failed"

# retention: delete backups older than RETENTION_DAYS
log "cleaning old backups"
find "$BACKUP_DST" -maxdepth 1 -type d -mtime +$RETENTION_DAYS -exec rm -rf {} + \
    || log "WARN: cleanup had issues"

log "backup complete: $target"
du -sh "$target" | tee -a "$LOGFILE"

How It Works

  1. Lock file prevents overlapping runs
  2. rsync with --link-dest creates space-efficient incrementals
  3. find + mtime removes backups older than 7 days
  4. All output goes to $LOGFILE for auditing

Cron Entry

0 2 * * * /opt/scripts/backup.sh

Runs daily at 2 AM.


Testing Before Cron

Always test manually first:

sudo /opt/scripts/backup.sh
tail -20 /var/log/backup.log

Verify the lock, rsync, and retention all work.


Next → Log Rotation & Cleanup

Updated: