Skip to content

Backup and Recovery

Comprehensive guide for protecting your security data and recovering from failures.

Time to read: ~10 min Prerequisites: Container Setup


What to Back Up

The Home Security Intelligence system stores data in multiple locations:

Data Type Location Priority
PostgreSQL Database postgres_data volume Critical
Generated Media ./backend/data/ High
Configuration .env Critical
Camera FTP Uploads ${FOSCAM_BASE_PATH:-/export/foscam} Medium

[!NOTE] Redis is ephemeral cache - it does not require backup.

Database Tables

Table Description
cameras Camera configuration and status
events Security events with AI analysis
detections Object detection results
alerts Alert history and status
alert_rules User-defined alert rules
zones Camera zone definitions
activity_baselines Anomaly detection baselines
class_baselines Object class frequency baselines
audit_logs Security audit trail
gpu_stats GPU performance history
api_keys API authentication keys

Quick Backup Commands

Database Backup

# Docker - compressed custom format (recommended)
docker compose -f docker-compose.prod.yml exec -T postgres pg_dump -U security -d security \
    --format=custom --compress=9 \
    > backup_$(date +%Y%m%d).dump

# Podman
podman-compose -f docker-compose.prod.yml exec -T postgres pg_dump -U security -d security \
    --format=custom --compress=9 \
    > backup_$(date +%Y%m%d).dump

# Plain SQL format
docker compose -f docker-compose.prod.yml exec -T postgres pg_dump -U security security > backup.sql

File Backup

# Full generated media directory (thumbnails, clips, logs, etc.)
tar -czvf files_$(date +%Y%m%d).tar.gz backend/data/

# Clips only (if you generate/store clips)
tar -czvf clips_$(date +%Y%m%d).tar.gz backend/data/clips/ || true

Configuration Backup

# Save .env and any customizations
cp .env .env.backup_$(date +%Y%m%d)

Daily Automated Backup

Create /opt/hsi-backup/backup.sh:

#!/bin/bash
set -euo pipefail

BACKUP_DIR="/opt/hsi-backup/daily"
RETENTION_DAYS=30
DATE=$(date +%Y-%m-%d_%H%M%S)
PROJECT_DIR="/path/to/home_security_intelligence"

mkdir -p "${BACKUP_DIR}"

echo "[$(date)] Starting backup..."

# Database
docker compose -f "${PROJECT_DIR}/docker-compose.prod.yml" exec -T postgres pg_dump -U security -d security \
    --format=custom --compress=9 \
    > "${BACKUP_DIR}/database_${DATE}.dump"

# Files
tar -czf "${BACKUP_DIR}/files_${DATE}.tar.gz" \
    -C "${PROJECT_DIR}/backend" data/ \
    --exclude='data/logs/*.log.*'

# Config
tar -czf "${BACKUP_DIR}/config_${DATE}.tar.gz" \
    -C "${PROJECT_DIR}" .env

# Cleanup old backups
find "${BACKUP_DIR}" -name "*.dump" -mtime +${RETENTION_DAYS} -delete
find "${BACKUP_DIR}" -name "*.tar.gz" -mtime +${RETENTION_DAYS} -delete

echo "[$(date)] Backup complete"

Schedule with cron:

chmod +x /opt/hsi-backup/backup.sh

# Add to crontab - runs daily at 2 AM
0 2 * * * /opt/hsi-backup/backup.sh >> /var/log/hsi-backup.log 2>&1

Recovery Procedures

Full System Recovery

Estimated time: 30-60 minutes

  1. Install prerequisites and clone repo
git clone https://github.com/your-org/home-security-intelligence.git
cd home-security-intelligence
  1. Restore configuration
tar -xzf config_backup.tar.gz
  1. Start database
docker compose -f docker-compose.prod.yml up -d postgres redis
# Wait for healthy
docker compose -f docker-compose.prod.yml ps
  1. Restore database
docker compose -f docker-compose.prod.yml exec -T postgres pg_restore \
    -U security -d security --clean --if-exists \
    < backup.dump
  1. Restore files
tar -xzf files_backup.tar.gz -C backend/
chown -R 1000:1000 backend/data/
  1. Start all services
docker compose -f docker-compose.prod.yml up -d
  1. Verify
    curl http://localhost:8000/api/system/health/ready
    docker exec postgres psql -U security -d security -c "SELECT COUNT(*) FROM events;"
    

Database-Only Recovery

# Stop backend
docker compose -f docker-compose.prod.yml stop backend

# Drop and recreate database
docker compose -f docker-compose.prod.yml exec -T postgres psql -U security -c "DROP DATABASE security;"
docker compose -f docker-compose.prod.yml exec -T postgres psql -U security -c "CREATE DATABASE security;"

# Restore
docker compose -f docker-compose.prod.yml exec -T postgres pg_restore -U security -d security < backup.dump

# Restart
docker compose -f docker-compose.prod.yml up -d backend

File-Only Recovery

docker compose -f docker-compose.prod.yml stop backend
tar -xzf files_backup.tar.gz -C backend/
chown -R 1000:1000 backend/data/
docker compose -f docker-compose.prod.yml up -d backend

Disaster Recovery Checklist

Pre-Recovery

  • [ ] Backup files accessible and verified
  • [ ] New server meets requirements
  • [ ] Docker/Podman + NVIDIA Container Toolkit installed
  • [ ] Sufficient storage space

Recovery Steps

  • [ ] Clone repository
  • [ ] Restore .env configuration
  • [ ] Start PostgreSQL and Redis
  • [ ] Verify database containers healthy
  • [ ] Restore database from backup
  • [ ] Restore file backups
  • [ ] Fix file permissions
  • [ ] Start all services
  • [ ] Verify all containers healthy

Post-Recovery Verification

  • [ ] API health check: curl localhost:8000/api/system/health/ready
  • [ ] Frontend loads: curl localhost:5173
  • [ ] Event count matches expected
  • [ ] Camera list correct
  • [ ] Detection images load
  • [ ] Alert rules present

Backup Verification

Test backups regularly:

# Verify backup structure
pg_restore --list backup.dump > /dev/null && echo "OK"

# Check backup size (should be > 1KB)
ls -lh backup.dump

Offsite Backup

For disaster recovery, store backups offsite:

# AWS S3
aws s3 sync /opt/hsi-backup/ s3://your-bucket/hsi-backups/

# rsync to remote server
rsync -avz /opt/hsi-backup/ user@remote:/backups/hsi/

Recovery Testing

[!IMPORTANT] Test your recovery procedures monthly. An untested backup is not a backup.

  1. Create a test environment (VM or separate server)
  2. Restore from backup following full recovery procedure
  3. Verify data integrity and functionality
  4. Document results
  5. Destroy test environment

Next Steps


See Also


Back to Operator Hub