Skip to content

Database Backups

Griffen Fargo edited this page Jun 30, 2026 · 3 revisions

Database Backups

Backup and restore procedures for Postgres, Neo4j, MySQL, and SQLite databases managed by strut.

Quick Reference

# Create backups
strut my-stack backup postgres --env prod
strut my-stack backup neo4j --env prod
strut my-stack backup mysql --env prod
strut my-stack backup sqlite --env prod
strut my-stack backup all --env prod

# Pull production data to local
strut my-stack db:pull --env prod
strut my-stack db:pull postgres --env prod
strut my-stack db:pull --env prod --download-only

# Push local data to production (⚠️ overwrites remote)
strut my-stack db:push postgres --env prod --file backups/postgres-20260303.sql
strut my-stack db:push postgres --env prod --file backups/postgres.sql --dry-run

Backup Verification

# Verify a specific backup
strut my-stack backup verify backups/postgres-20260315.sql --env prod

# Verify all backups
strut my-stack backup verify-all --env prod

# View health scores (0-100)
strut my-stack backup health --env prod

Scheduling & Retention

backup.conf

Each stack has a backup.conf controlling schedules and retention:

BACKUP_POSTGRES=true
BACKUP_SCHEDULE_POSTGRES="0 2 * * *"   # 02:00 UTC daily
BACKUP_RETAIN_DAYS=30
BACKUP_RETAIN_COUNT=10

BACKUP_NEO4J=true
BACKUP_SCHEDULE_NEO4J="0 3 * * *"

BACKUP_SQLITE=true
BACKUP_SQLITE_USE_DOCKER=true          # SQLite inside Docker volume

# Offsite sync (since v0.16.0)
BACKUP_OFFSITE=s3                      # s3 | r2 | b2 | none (default)
BACKUP_OFFSITE_BUCKET=my-backups
BACKUP_OFFSITE_PREFIX=my-stack         # default: stack name
BACKUP_OFFSITE_RETENTION_DAYS=90

Offsite Backup Sync (since v0.16.0)

After each successful local backup, strut can push the artefact to S3, Cloudflare R2, or Backblaze B2. Sync failures are non-fatal — they warn and the local backup still succeeds.

Commands

strut my-stack backup offsite status --env prod          # Show provider config + enabled?
strut my-stack backup offsite sync --env prod            # Backfill: upload every local file
strut my-stack backup offsite list --env prod            # List remote objects (provider-native)
strut my-stack backup offsite restore <filename> --env prod   # Pull one file down

The remote key layout is <prefix>/<basename> — no directory nesting inside the bucket.

Provider Setup

S3 — AWS CLI, credentials via AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, IAM role, or ~/.aws/:

# backup.conf
BACKUP_OFFSITE=s3
BACKUP_OFFSITE_BUCKET=my-backups

R2 — Cloudflare R2 uses the AWS CLI against an R2 endpoint. Set R2_ACCOUNT_ID so strut injects --endpoint-url=https://<acct>.r2.cloudflarestorage.com. Credentials still come from the standard AWS env vars (R2 tokens map to them):

# backup.conf
BACKUP_OFFSITE=r2
BACKUP_OFFSITE_BUCKET=my-bucket

# Env (or .prod.env / shell)
export R2_ACCOUNT_ID=abc123...
export AWS_ACCESS_KEY_ID=<r2-access-key>
export AWS_SECRET_ACCESS_KEY=<r2-secret-key>

B2 — Backblaze B2 CLI with app keys:

# backup.conf
BACKUP_OFFSITE=b2
BACKUP_OFFSITE_BUCKET=my-bucket

# Env
export B2_APPLICATION_KEY_ID=<key-id>
export B2_APPLICATION_KEY=<app-key>

If the required CLI (aws or b2) isn't on PATH, strut warns once and treats offsite as disabled rather than failing the backup.

Schedule Management

strut my-stack backup schedule install-defaults --env prod
strut my-stack backup schedule list --env prod
strut my-stack backup retention enforce --env prod

Common Workflows

Refresh Local Dev Environment

strut my-stack db:pull --env prod

Pulls the latest backup from VPS and restores it locally.

Test Migration Locally Before Production

strut my-stack db:pull --env prod
strut my-stack migrate postgres --up --env local
# Test locally, then apply to prod:
strut my-stack migrate postgres --up --env prod

Recover from Bad Migration

strut my-stack restore backups/postgres-20260303.sql --env prod
strut my-stack health --env prod

Supported Databases

Database Backup Method Container Requirement
Postgres pg_dump Postgres container running
Neo4j neo4j-admin dump Neo4j container running
MySQL mysqldump MySQL container running
SQLite File copy Volume accessible (or BACKUP_SQLITE_USE_DOCKER=true)

Troubleshooting

Backup Fails

# Check disk space
strut my-stack exec "df -h /" --env prod

# Check database is running
strut my-stack exec "docker compose --project-name prod exec postgres pg_isready" --env prod

# Check logs
strut my-stack logs postgres --tail 50 --env prod

Pull/Push Fails

# Verify SSH access
strut my-stack shell --env prod

# Check VPS_HOST is set
grep VPS_HOST .prod.env

Related Pages

Clone this wiki locally