Backup Rotation Script
Build a Bash script that backs up chosen folders, and optionally a Docker volume (such as a database's data), into dated archives, keeps only the most recent ones (for example the last 7 days), and can copy each new backup to another server over SSH. It's safe to run every night from cron: it checks every archive after creating it, never deletes old backups before the new one is confirmed good, logs what it did, and uses awk to print a tidy summary of the backups it has. It's a good first shell scripting project: you'll learn tar and gzip, working with dates in Bash, loops and conditions, the Docker CLI, scp and ssh, awk for reports, and writing scripts that fail safely.
- Estimate
- ~7.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
GNU Awk · OpenSSH · Docker CLI
Project roadmap
- 01
Define the script's behavior
~1hWrite README.md: a config file with the folders to back up, an optional Docker volume name, the backup folder, how many days to keep, and an optional remote destination (user@host:path); the archive names (backup-2026-03-15-0200.tar.gz); and the order of steps (create, verify, copy, then delete old ones). Done when: README.md describes the config, names and steps.
- 02
Create and verify archives
~1.5hWrite backup.sh with set -euo pipefail. Create the archive with tar -czf from the configured folders, writing to a temporary name first. Verify it by listing its contents with tar -tzf, and only then rename it to its final name and write a sha256sum file next to it. Stop with a clear message when a folder is missing. Done when: running the script creates a verified archive and its checksum.
- 03
Back up a Docker volume
~1hWhen a volume is configured, back it up with a short-lived container: docker run --rm -v VOLUME:/data:ro -v BACKUP_DIR:/backup alpine tar -czf /backup/NAME.tar.gz -C /data . Check the volume exists first with docker volume inspect, and verify the archive the same way. Done when: a test volume is backed up into a verified archive.
- 04
Delete old backups safely
~1hAfter a successful backup, find archives older than the retention period (from their names or with find -mtime) and delete them along with their checksum files, never touching the newest one and never running this step when the backup failed. Add --dry-run to show what would be deleted. Done when: old backups are deleted only after a good new backup, and --dry-run deletes nothing.
- 05
Copy to a remote server and summarize
~1.5hWhen a remote destination is set, copy the archive and checksum with scp (using a key and BatchMode), and verify the remote checksum over ssh with sha256sum -c. Log every step with timestamps to a log file. Add a list command that uses awk on ls output to print a table of backups with their date, size and total disk use. Done when: backups reach the remote server verified, and the list command shows a tidy table.
- 06
Test it
~1.5hTest with a temporary folder and fake old backups (with dates set by touch -d): creation, verification, retention, dry runs, a missing folder, and a failed backup not deleting anything. Write the tests with bats-core, and run shellcheck. Add an example crontab line to README.md. Done when: the tests pass, and shellcheck reports no warnings.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack