Skip to content

Backups

Schedule

Automated backups run daily at 4:00 AM UTC via cron.

# View the cron job
crontab -l
# 0 4 * * * /opt/camlab/backup.sh >> /opt/camlab/backups/backup.log 2>&1

Backup Scope

graph LR
    cron["Cron<br>4 AM UTC"] --> script["backup.sh"]
    script --> db["MySQL<br>Databases x3"]
    script --> ghost["Ghost<br>Content x3"]
    script --> n8n["n8n<br>Data"]
    script --> runners["Runner<br>Configs x3"]
    script --> env[".env +<br>compose"]
    db & ghost & n8n & runners & env --> tar["camlab-backup-<br>DATE.tar.gz"]

What's Backed Up

Component Source Method
MySQL databases (x3) mysql container mysqldump all 3 Ghost databases
Ghost content (x3) ./ghost/<slug>/ tar archive of images, themes, data
n8n data ./n8n/data/ tar archive of n8n database + credentials
Runner configs (x3) ./runners/<slug>/claude-config/ tar archive of agent definitions + MCP configs
Environment file .env Direct copy
Docker Compose docker-compose.yml Direct copy

Backup Location

/opt/camlab/backups/
├── backup.log                           # Cron output log
├── camlab-backup-YYYY-MM-DD.tar.gz      # Daily archives
└── ...

Retention

Backups older than 7 days are automatically pruned by the backup script.

Restore Procedures

Full Restore

cd /opt/camlab

# Stop all services
docker compose down

# Extract backup
tar xzf backups/camlab-backup-YYYY-MM-DD.tar.gz -C /tmp/restore/

# Restore .env
cp /tmp/restore/.env /opt/camlab/.env

# Restore MySQL data
docker compose up -d mysql
# Wait for MySQL to be ready
docker exec -i mysql mysql -u root -p"<root-password>" < /tmp/restore/mysql-all-databases.sql

# Restore Ghost content
cp -r /tmp/restore/ghost/* /opt/camlab/ghost/

# Restore n8n data
cp -r /tmp/restore/n8n-data/* /opt/camlab/n8n/data/

# Restore runner configs
cp -r /tmp/restore/runners/* /opt/camlab/runners/

# Start everything
docker compose up -d

Single Database Restore

# Restore just one Ghost database
docker exec -i mysql mysql -u root -p"<root-password>" ghost_cam4 < /tmp/restore/ghost_cam4.sql

# Restart the Ghost instance
docker compose restart ghost-cam4

Single Blog Content Restore

# Restore images/themes for one blog
cp -r /tmp/restore/ghost/cam4/* /opt/camlab/ghost/cam4/

# Restart Ghost to pick up theme changes
docker compose restart ghost-cam4

Manual Backup

# Run the backup script manually
/opt/camlab/backup.sh

# Or just dump MySQL
docker exec mysql mysqldump -u root -p"<root-password>" --all-databases > /tmp/all-databases.sql

Verification

# Check backup file exists and has reasonable size
ls -lh /opt/camlab/backups/

# Check backup log for errors
tail -20 /opt/camlab/backups/backup.log

# Test extraction (dry run)
tar tzf /opt/camlab/backups/camlab-backup-YYYY-MM-DD.tar.gz | head -20