Part of: Backup & Disaster Recovery Kit by Datanest Digital
A comprehensive guide to designing, implementing, and maintaining a production backup strategy.
The foundational principle of data protection:
Primary Data (Production)
├── Copy 1: Local backup (same region, different server)
├── Copy 2: Cloud object storage (S3, B2, GCS)
└── Copy 3: Cross-region replica (different cloud region)
Modern best practice extends this to:
All backups should be encrypted before upload:
# AES-256-CBC with PBKDF2 key derivation
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 100000 \
-in backup.tar.zst \
-out backup.tar.zst.enc \
-pass env:ENCRYPTION_KEY| Practice | Description |
|---|---|
| Never store keys with backups | If an attacker gets your backups, they shouldn't also get the key |
| Use a secrets manager | AWS KMS, HashiCorp Vault, Azure Key Vault |
| Rotate keys periodically | At minimum annually; re-encrypt old backups with new keys |
| Document key recovery | Ensure multiple team members can access the decryption key |
| Test decryption regularly | Part of your monthly restore drill |
In addition to client-side encryption, enable S3-SSE:
# Enable default encryption on the bucket
aws s3api put-bucket-encryption \
--bucket my-backups \
--server-side-encryption-configuration '{
"Rules": [{
"ApplyServerSideEncryptionByDefault": {
"SSEAlgorithm": "aws:kms",
"KMSMasterKeyID": "alias/backup-key"
}
}]
}'A regional outage could affect both your primary data and your backups if they're in the same region.
# Enable versioning (required for replication)
aws s3api put-bucket-versioning \
--bucket my-backups \
--versioning-configuration Status=Enabled
# Configure replication
aws s3api put-bucket-replication \
--bucket my-backups \
--replication-configuration '{
"Role": "arn:aws:iam::123456789012:role/backup-replication-role",
"Rules": [{
"Status": "Enabled",
"Destination": {
"Bucket": "arn:aws:s3:::my-backups-eu-west-1",
"StorageClass": "STANDARD_IA"
}
}]
}'For maximum resilience, replicate to a different cloud provider:
# Use rclone to sync S3 to Backblaze B2
rclone sync s3:my-backups b2:my-backups-b2 \
--transfers=8 \
--checkers=16 \
--filter="+ *.dump.*" \
--filter="+ *.tar.*" \
--filter="- *"An untested backup is not a backup. Common failure modes:
┌─────────────────┐
│ Full DR Drill │ Quarterly
│ (end-to-end) │
├─────────────────┤
│ Restore Drill │ Monthly
│ (single system) │
├─────────────────┤
│ Integrity Check │ Weekly
│ (checksum + list)│
├─────────────────┤
│ Existence Check │ Daily
│ (file exists, │
│ size > 0) │
└─────────────────┘
# Run this on a schedule (weekly recommended)
./scripts/verify-backups.sh \
--bucket s3://my-backups \
--all \
--test-restore \
--report /var/log/backups/weekly-verification.json| Age | Storage Class | Cost (per GB/month) | Retrieval Time |
|---|---|---|---|
| 0-30 days | Standard / Standard-IA | $0.023 / $0.0125 | Immediate |
| 30-90 days | S3 Infrequent Access | $0.0125 | Immediate |
| 90-365 days | Glacier Instant Retrieval | $0.004 | Milliseconds |
| 1-5 years | Glacier Flexible | $0.0036 | 1-12 hours |
| 5+ years | Glacier Deep Archive | $0.00099 | 12-48 hours |
1. Compress before upload: zstd typically achieves 3-5x compression on database dumps
2. Use lifecycle policies: Automatically transition old backups to cheaper storage
3. Deduplicate: Use incremental backups (rsync --link-dest) to avoid storing duplicate data
4. Monitor backup sizes: Unexpected growth may indicate issues
5. Clean up old backups: Enforce retention policies to avoid indefinite growth
# PostgreSQL
./scripts/backup-postgres.sh --host db.prod --database myapp --bucket s3://backups/pg --encrypt
# MySQL
./scripts/backup-mysql.sh --host db.prod --database myapp --bucket s3://backups/mysql --encrypt
# Filesystem
./scripts/backup-filesystem.sh --source /data --destination s3://backups/files --encrypt
# Docker volumes
./scripts/backup-docker-volumes.sh --all --bucket s3://backups/volumes# PostgreSQL
./scripts/restore-postgres.sh --host db.new --database myapp --bucket s3://backups/pg --decrypt --create-db
# Filesystem
./scripts/restore-filesystem.sh --source s3://backups/files --destination /data --decrypt# Verify all backups
./scripts/verify-backups.sh --bucket s3://backups --all --test-restore --report report.jsonBattle-tested backup scripts and disaster recovery runbooks for production infrastructure.

![Shell]()
![Docker]()
Automate your backups, verify their integrity, and recover in minutes -- not hours.
Get the full Backup Disaster Recovery and unlock everything.
Get the complete guide with every chapter unlocked, including code samples, diagrams, and best practices.
Access all interactive tools with complete data, all workload profiles, and the full scenario library.
Downloadable source code, configuration files, and working examples from every chapter.
Free updates for life. Every new chapter, tool, and improvement included.