Learn 🧠 All Concepts (20) 🤖 What is an LLM? 📚 RAG Explained ⚡ AI Agents 💻 Run AI Locally 🇮🇳 AI in India 📖 Learn Tracks 🔧 DevOps Track ⚙️ AI Ops Track 🗺️ AI Engineer Roadmap
Tools 🔧 AI Tools Directory 🔓 Open Source AI ⭐ Top GitHub Repos ✦ Claude Skill Repos 🚀 Ready-to-Deploy Projects
Build 🏗️ Build Hub 🎯 Master Prompts 🧩 RAG Agents 🚀 App Megaprompts
Workflows ⚡ All Workflows (22) 🎥 Text to Video 🎞️ Image to Video 🔊 Text to Speech ♻️ Automation
Resources 🧪 Colab Notebooks ⚙️ n8n Workflows 📈 Algo Trading 💰 Passive Income
🗂️ Browse All Topics About AItheGuru
Learn Linux for Production Support Meera builds the backup system nobody questioned
Linux for Production Support Ch 28 / 32 Advanced
🗄️

Meera builds the backup system nobody questioned

tar, rsync, pg_dump, rclone — backups that actually work when you need them

⏱ 14 min 6 commands 5 takeaways
🗄️
In this chapter
Meera
DBA who learned backup the hard way
The story

Meera woke up on a Wednesday morning to find the production database had been accidentally dropped. A developer ran DROP DATABASE on production instead of staging. Everyone had assumed backups existed. Nobody had verified they actually worked.

Meera spent the next 8 hours rebuilding the database from application logs and whatever data she could find. The company lost 6 hours of transaction data.

The next morning she built a proper backup system. Three months later she tested it. It restored in 12 minutes. That test saved the company when the database server's SSD failed 6 weeks after the test.

THE BACKUP RULES MEERA FOLLOWED

Rule 1: 3-2-1 backup strategy.

3 copies of data. 2 different storage media. 1 offsite copy.

Rule 2: A backup you have never tested is not a backup.

Test restore every month.

Rule 3: Automate everything. Manual backups get forgotten.

BACKING UP FILES — TAR

tar is the standard Linux archiving tool. It bundles files into a single archive, optionally compressed.

# Create a compressed backup:
tar -czf backup_$(date +%Y%m%d).tar.gz /opt/app/config/ /opt/app/data/
# What the flags mean:
# c = create, z = gzip compress, f = filename
# List contents without extracting:
tar -tzf backup_20260316.tar.gz
# Extract to a specific directory:
tar -xzf backup_20260316.tar.gz -C /restore/
# Incremental backup (only changed files since last backup):
tar -czf incremental_$(date +%Y%m%d).tar.gz \
    --newer-mtime="2026-03-15" \
    /opt/app/data/
# Exclude directories:
tar -czf backup.tar.gz /opt/app/ --exclude=/opt/app/logs --exclude=/opt/app/tmp

RSYNC — SMARTER FILE SYNC AND BACKUP

rsync only transfers what changed. Ideal for large directories where most files do not change daily.

# Sync a directory to a backup location:
rsync -avz /opt/app/ /backup/app/
# a = archive (preserves permissions, timestamps, symlinks)
# v = verbose
# z = compress during transfer
# Sync to a remote server:
rsync -avz /opt/app/ backup-server:/backup/app/
# Mirror exactly (delete files on destination that no longer exist on source):
rsync -avz --delete /opt/app/ backup-server:/backup/app/
# Dry run (show what would happen without doing it):
rsync -avzn --delete /opt/app/ backup-server:/backup/app/
# Exclude certain files:
rsync -avz --exclude='*.log' --exclude='tmp/' /opt/app/ /backup/app/

POSTGRESQL BACKUPS

# Dump a single database:
pg_dump dbname > backup_$(date +%Y%m%d).sql
# Compressed dump:
pg_dump dbname | gzip > backup_$(date +%Y%m%d).sql.gz
# Dump all databases:
pg_dumpall > all_databases_$(date +%Y%m%d).sql
# Restore from dump:
psql dbname < backup_20260316.sql
# or compressed:
gunzip -c backup_20260316.sql.gz | psql dbname
# Custom format (faster restore, allows parallel restore):
pg_dump -Fc dbname > backup_$(date +%Y%m%d).dump
pg_restore -d dbname backup_20260316.dump
# Automated daily backup in cron:
0 2 * * * postgres pg_dump appdb | gzip > /backups/appdb_$(date +\%Y\%m\%d).sql.gz && find /backups -name "*.gz" -mtime +30 -delete

MYSQL BACKUPS

# Dump a database:
mysqldump -u root -p dbname > backup_$(date +%Y%m%d).sql
# Compressed:
mysqldump -u root -p dbname | gzip > backup_$(date +%Y%m%d).sql.gz
# Restore:
mysql -u root -p dbname < backup_20260316.sql
# All databases:
mysqldump -u root -p --all-databases > all_$(date +%Y%m%d).sql

TESTING YOUR RESTORE — THE MOST IMPORTANT STEP

# Monthly restore test script:
#!/bin/bash
set -euo pipefail
LOG="/var/log/restore-test-$(date +%Y%m%d).log"
echo "$(date): Starting restore test" | tee -a $LOG
# Get latest backup:
LATEST=$(ls -t /backups/appdb_*.sql.gz | head -1)
echo "$(date): Using backup: $LATEST" | tee -a $LOG
# Create a test database:
createdb test_restore_$(date +%Y%m%d)
# Restore into it:
gunzip -c "$LATEST" | psql test_restore_$(date +%Y%m%d)
# Verify row counts match production:
PROD_COUNT=$(psql appdb -t -c "SELECT COUNT(*) FROM users;")
TEST_COUNT=$(psql test_restore_$(date +%Y%m%d) -t -c "SELECT COUNT(*) FROM users;")
if [ "$PROD_COUNT" = "$TEST_COUNT" ]; then
    echo "$(date): RESTORE TEST PASSED — counts match: $PROD_COUNT" | tee -a $LOG
else
    echo "$(date): RESTORE TEST FAILED — prod: $PROD_COUNT test: $TEST_COUNT" | tee -a $LOG
    exit 1
fi
# Clean up test database:
dropdb test_restore_$(date +%Y%m%d)
echo "$(date): Restore test complete" | tee -a $LOG

OFFSITE BACKUP — RCLONE TO S3

rclone syncs files to cloud storage (AWS S3, Google Cloud Storage, Backblaze B2):

# Install:
curl https://rclone.org/install.sh | sudo bash
# Configure (interactive setup):
rclone config
# Copy backup to S3:
rclone copy /backups/appdb_$(date +%Y%m%d).sql.gz s3:my-backup-bucket/databases/
# Sync entire backup directory:
rclone sync /backups/ s3:my-backup-bucket/
# Cost estimate for Indian companies:
# AWS S3 ap-south-1 (Mumbai): ~$0.023/GB/month
# 100GB of backups = ~$2.30/month = ~₹190/month

The morning after her restore test succeeded, Meera sent a message in the company Slack: Restore test passed. 12 minutes to full recovery. The backup system works. Her manager wrote back: this is the first time I have felt genuinely safe about our data in 3 years.

Key takeaways

3-2-1 backup rule: 3 copies, 2 different media, 1 offsite — a backup that only lives on the same server is not a backup

Test your restore every month — an untested backup is just a file you hope works

pg_dump -Fc creates a custom format dump that restores faster and supports parallel restore

rsync --delete mirrors a directory exactly and only transfers changed files — much faster than tar for large directories

rclone sync to S3 ap-south-1 Mumbai costs around 190 rupees per month for 100GB — offsite backup is affordable

Commands from this chapter
$ tar -czf backup_$(date +%Y%m%d).tar.gz /opt/app/config/
Create compressed timestamped backup of config directory
$ rsync -avz --delete /opt/app/ backup-server:/backup/app/
Mirror directory to backup server, only transferring changes
$ pg_dump -Fc appdb > backup_$(date +%Y%m%d).dump
PostgreSQL custom format dump — faster restore than SQL format
$ pg_restore -d appdb backup_20260316.dump
Restore PostgreSQL from custom format dump
$ rclone sync /backups/ s3:my-bucket/
Sync backup directory to AWS S3
$ find /backups -name '*.gz' -mtime +30 -delete
Delete backup files older than 30 days