Automation projects
Build a backup wrapper
Validate source and destination, create a dated archive, verify it, and report a clear result.
10 minute lesson
This module assembles the course pieces into small real tools, starting with a backup wrapper. The wrapper coordinates existing tools: validate the inputs, run tar, verify the result, report clearly. It should not pretend that creating an archive is a complete offsite backup.
The core operation
#!/usr/bin/env bash
set -euo pipefail
source_directory=${1:?source directory required}
destination=${2:?destination required}
archive="$destination/backup-$(date -u +%Y%m%dT%H%M%SZ).tar.gz"
tar -czf "$archive" -C "$source_directory" .
tar -tzf "$archive" >/dev/null
printf 'created %s\n' "$archive"
The ${1:?...} expansions reject missing arguments with a clear message and a non-zero status, so a half-configured run never starts. The timestamp from date -u +%Y%m%dT%H%M%SZ makes archive names sort chronologically, and two runs can’t silently overwrite each other.
tar -C "$source_directory" . changes into the source before archiving, so the archive stores relative paths. The second tar -tzf lists the finished archive and discards the listing: reading every entry back pushes the whole file through gzip, so a truncated or corrupt archive fails here — not on restore day.
./backup-wrapper /var/www/site /mnt/backups
# created /mnt/backups/backup-20260803T151530Z.tar.gz
Test the unhappy paths
Test with spaces in paths, insufficient permissions, a full destination, and a restore into a temporary directory:
./backup-wrapper '/var/www/my site' /mnt/backups # spaces must survive
./backup-wrapper /root/private /mnt/backups # tar must fail loudly, status non-zero
mkdir -p /tmp/restore-test
tar -xzf /mnt/backups/backup-20260803T151530Z.tar.gz -C /tmp/restore-test
The restore drill is the step people skip. An archive nobody has ever extracted is a hope, not a backup. Diff a few restored files against the originals before you trust the wrapper with anything real.
Know the wrapper’s limits
Do not archive a changing database and assume consistency. tar reads files one at a time, so a database writing during the walk produces an archive whose files never coexisted — it may not restore at all. Use the database’s backup mechanism, like pg_dump or mysqldump, and archive its output instead.
And a .tar.gz sitting on the same machine protects against mistakes, not disk failure. Copying archives somewhere independent is the missing half of the job.
Lesson completed