# VAPORA Backup & Recovery Scripts Automated backup and recovery procedures for VAPORA using Nushell 0.109.0+. **Dual Backup Strategy**: - **S3**: Direct file uploads with AES-256 encryption - **Restic**: Incremental, deduplicated backups with compression --- ## Scripts Overview ### Backup Scripts | Script | Purpose | Schedule | Target | |--------|---------|----------|--------| | `database-backup.nu` | Export SurrealDB to S3 (compressed + encrypted) | Manual or Hourly | S3 | | `config-backup.nu` | Backup Kubernetes ConfigMaps/Secrets | Manual or Daily | S3 | | `restic-backup.nu` | Incremental backup to Restic repository | Manual | Restic | | `orchestrate-backup-recovery.nu` | Coordinate all backup types | CronJob | S3 + Restic | ### Recovery Scripts | Script | Purpose | Input | |--------|---------|-------| | `database-recovery.nu` | Restore SurrealDB from S3 backup | Encrypted S3 file | | `orchestrate-backup-recovery.nu` | One-command recovery | S3 or Restic location | ### Verification | Script | Purpose | Checks | |--------|---------|--------| | `verify-backup-health.nu` | Health check for backup infrastructure | S3, Restic, DB, freshness, rotation | --- ## Quick Start ### Local Backup ```bash # Set environment export SURREAL_URL="ws://localhost:8000" export SURREAL_PASS="your-password" export S3_BUCKET="vapora-backups" export ENCRYPTION_KEY_FILE="/path/to/key" # Run full backup nu scripts/orchestrate-backup-recovery.nu \ --operation backup \ --mode full \ --surreal-url "$SURREAL_URL" \ --surreal-pass "$SURREAL_PASS" \ --s3-bucket "$S3_BUCKET" \ --encryption-key "$ENCRYPTION_KEY_FILE" \ --iac-dir "provisioning" ``` ### Local Recovery ```bash # Restore from S3 backup nu scripts/orchestrate-backup-recovery.nu \ --operation recovery \ --s3-location "s3://vapora-backups/backups/database/database-20260112-010000.sql.gz.enc" \ --encryption-key "$ENCRYPTION_KEY_FILE" \ --surreal-url "$SURREAL_URL" \ --surreal-pass "$SURREAL_PASS" ``` ### Health Check ```bash nu scripts/verify-backup-health.nu \ --s3-bucket "$S3_BUCKET" \ --surreal-url "$SURREAL_URL" \ --surreal-pass "$SURREAL_PASS" ``` --- ## Kubernetes Automation CronJobs defined in `kubernetes/09-backup-cronjobs.yaml`: - **Hourly** (00:00 UTC): Database backup (S3 + Restic) - **Daily** (02:00 UTC): Configuration backup - **Daily** (03:00 UTC): Health verification - **Monthly** (04:00 first day): Snapshot rotation/cleanup **Deploy**: ```bash kubectl apply -f kubernetes/09-backup-cronjobs.yaml ``` **Monitor**: ```bash kubectl get cronjobs -n vapora kubectl logs -n vapora -l backup-type=database -f ``` --- ## Features ✅ **Dual backup approach** (S3 + Restic) ✅ **Encryption** (AES-256 at rest, encrypted transfer) ✅ **Compression** (gzip for S3, built-in for Restic) ✅ **Incremental** (Restic only - no duplicate data) ✅ **Verification** (post-backup integrity checks) ✅ **Retention** (daily/weekly/monthly policies) ✅ **Health checks** (automated daily verification) ✅ **Recovery** (one-command restore) ✅ **Kubernetes native** (CronJobs, RBAC, secrets) --- ## Implementation Details All scripts follow **NUSHELL_GUIDELINES.md (0.109.0+)** strictly: ✓ Function signatures with BOTH `:` and `->` ✓ NO mutable variables (use `reduce --fold`) ✓ External commands with `^` prefix ✓ Error handling with `do { } | complete` ✓ Variable interpolation with `[$var]` for variables, `($expr)` for expressions ✓ NO try-catch blocks ✓ NO type annotations on boolean flags ✓ Pipelines in conditionals are parenthesized --- ## Configuration ### Environment Variables **SurrealDB**: ```bash SURREAL_URL=ws://localhost:8000 SURREAL_USER=root SURREAL_PASS= ``` **AWS S3**: ```bash S3_BUCKET=vapora-backups AWS_REGION=us-east-1 AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= ``` **Restic**: ```bash RESTIC_REPO=s3:s3.amazonaws.com/vapora-backups/restic RESTIC_PASSWORD= ``` **Encryption**: ```bash ENCRYPTION_KEY_FILE=/path/to/encryption.key ``` ### Kubernetes Secrets ```bash # Database credentials kubectl create secret generic vapora-secrets \ --from-literal=surreal_password="$SURREAL_PASS" \ --from-literal=restic_password="$RESTIC_PASSWORD" \ -n vapora # AWS credentials kubectl create secret generic vapora-aws-credentials \ --from-literal=access_key_id="$AWS_ACCESS_KEY_ID" \ --from-literal=secret_access_key="$AWS_SECRET_ACCESS_KEY" \ -n vapora # Encryption key kubectl create secret generic vapora-encryption-key \ --from-file=encryption.key=/path/to/encryption.key \ -n vapora ``` --- ## Backup Locations ### S3 Paths ``` s3://vapora-backups/ ├── backups/ │ ├── database/ │ │ └── database-20260112-010000.sql.gz.enc │ └── config/ │ └── configs-20260112-020000.tar.gz └── restic/ ├── data/ ├── index/ ├── snapshots/ └── config ``` ### Restic Repository ``` s3://vapora-backups/restic/ ├── data/ # Backup data files ├── index/ # Index files ├── snapshots/ # Snapshot metadata └── config # Repository config ``` --- ## Recovery Procedures ### Database Recovery (S3) 1. Download encrypted backup from S3 2. Decrypt with AES-256 key 3. Decompress backup 4. Scale down StatefulSet 5. Delete current PVC 6. Scale up StatefulSet (creates new PVC) 7. Import backup to database 8. Verify data integrity **Time**: 30-60 seconds (depends on backup size) ### Restic Recovery ```bash # List available snapshots restic -r "$RESTIC_REPO" snapshots # Restore specific snapshot to directory restic -r "$RESTIC_REPO" restore --target /recovery ``` --- ## Troubleshooting ### Backup Fails **Check logs**: ```bash kubectl logs -n vapora -l backup-type=database --tail=100 ``` **Verify credentials**: ```bash # S3 aws s3 ls s3://vapora-backups/ # Restic RESTIC_PASSWORD="$RESTIC_PASSWORD" restic -r "$RESTIC_REPO" list snapshots ``` ### Recovery Fails **Ensure database is stopped**: ```bash kubectl scale statefulset surrealdb --replicas=0 -n vapora ``` **Verify PVC deleted**: ```bash kubectl get pvc -n vapora ``` **Check encryption key exists**: ```bash kubectl get secrets -n vapora vapora-encryption-key ``` ### Health Check Fails **Run detailed check**: ```bash nu scripts/verify-backup-health.nu \ --s3-bucket "$S3_BUCKET" \ --surreal-url "$SURREAL_URL" \ --surreal-pass "$SURREAL_PASS" \ --max-age-hours 25 ``` --- ## Integration with Disaster Recovery These scripts implement the backup strategy defined in: - `docs/disaster-recovery/backup-strategy.md` - `docs/disaster-recovery/database-recovery-procedures.md` See `docs/operations/backup-recovery-automation.md` for comprehensive integration guide. --- ## Support **Documentation**: - Backup Strategy: `docs/disaster-recovery/backup-strategy.md` - Disaster Recovery: `docs/disaster-recovery/README.md` - Operations Guide: `docs/operations/README.md` **Issues**: - Check logs: `kubectl logs -n vapora -l backup-type=database` - Verify configuration: Check all environment variables are set - Test connectivity: `aws s3 ls`, `surreal list namespaces` --- **Last Updated**: January 12, 2026 **Nushell Version**: 0.109.0+ **Status**: Production-Ready