Skip to main content

Backup and Restore Guide

This guide provides comprehensive documentation for backing up, restoring, and migrating database records and media assets in the containerized Scannersky stack.


Architecture Overview & Default Paths

In the Docker deployment stack:

  • Database (postgres:16): Data is stored inside container volume postgres_data. Backups are generated via containerized pg_dump commands directly inside the postgres container.
  • Media Assets (minio:latest): Uploaded student photos (persons/), digital signatures (signatures/), profile pictures (profiles/), and rendered badges (id_cards/) are stored in the scannersky-media MinIO object storage bucket.
  • Zero Host Dependencies: Neither PostgreSQL nor MinIO client utilities are required on the host OS; all operations run through containerized bash scripts in deploy/scripts/.

Default Backup Paths

When no custom paths are specified, all backup and restore operations default to your user home directory (~/):

  • Database Backup Root: ~/db_backups/postgres_dumps/
  • Media Backup Root: ~/media_backups/media/

1. Automated Backup Workflow

The backup script [deploy/scripts/backup-docker.sh] supports backing up database dumps, MinIO media assets, or both.

Backup Commands

# 1. Backup MEDIA ONLY (exports MinIO bucket into single-instance ~/media_backups/media/)
bash ./deploy/scripts/backup-docker.sh --media-only

# 2. Backup DATABASE ONLY (exports PostgreSQL dump into ~/db_backups/postgres_dumps/scannersky_YYYYMMDD_HHMMSS.sql)
bash ./deploy/scripts/backup-docker.sh --db-only

# 3. Backup BOTH Database & Media (default)
bash ./deploy/scripts/backup-docker.sh --all

Single-Instance Media Backup Behavior

To prevent disk space exhaustion from duplicate media archives, media backups maintain a single active instance at ~/media_backups/media/:

  1. Automatic Overwrite: Each time backup-docker.sh (or --media-only) runs, it overwrites the previous media copy in ~/media_backups/media/ with the latest files from the MinIO scannersky-media bucket.
  2. Metadata Timestamping: Writes a .backup_info metadata file into ~/media_backups/media/.backup_info recording the exact creation date and time (BACKUP_DATE and BACKUP_TIMESTAMP).

Database Dump Retention Policy

PostgreSQL SQL dumps are saved with timestamps: ~/db_backups/postgres_dumps/scannersky_YYYYMMDD_HHMMSS.sql.

  • Retention: Old .sql dump files older than 7 days are automatically purged during backup execution (configurable via RETENTION_DAYS).

Automated Nightly Crontab Schedule

To enable automated nightly backups at 2:00 AM, add this entry to your system crontab (crontab -e):

0 2 * * * ~/scannersky-django/deploy/scripts/backup-docker.sh >> ~/db_backups/backup.log 2>&1

2. Unified Restoration Workflow

The restoration script [deploy/scripts/restore-docker.sh] provides interactive database selection and media date/time confirmation:

# 1. Restore BOTH database and media in one step (Recommended)
bash ./deploy/scripts/restore-docker.sh --all

# 2. Restore PostgreSQL database dump only
bash ./deploy/scripts/restore-docker.sh --db-only

# 3. Restore Media backup directory into MinIO bucket only
bash ./deploy/scripts/restore-docker.sh --media-only

3. Interactive Database Restoration (--db-only)

Interactive Dump Selection Menu

When DUMP_FILE is not specified, restore-docker.sh scans ~/db_backups/postgres_dumps/, lists available SQL dump files with file sizes and creation timestamps, and presents an interactive choice menu:

=== Available Database Dumps ===
1) scannersky_20260807_143000.sql (12.4 MB) - [Aug 07 14:30]
2) scannersky_20260805_015853.sql (11.8 MB) - [Aug 05 01:58]
Select dump number [1-2] (default: 1):
  • Pressing Enter (or selecting 1) automatically chooses the latest valid dump file.
  • Typing a number selects that specific dump.
  • Entering a file path uses that specific custom SQL file.

Confirmation Prompt & Execution

Before modifying the database, the script displays the target dump details and asks for confirmation:

=== Database Restore ===
Target Database: scannersky
Dump File: /home/scannersking/db_backups/postgres_dumps/scannersky_20260807_143000.sql (12.4 MB) - [Aug 07 14:30]
Continue restoring database from scannersky_20260807_143000.sql? [y/N]: y

During restoration:

  1. Executes DROP DATABASE IF EXISTS "scannersky" WITH (FORCE); to safely terminate all active Django connections.
  2. Recreates the scannersky database.
  3. Streams the SQL dump directly into the containerized postgres instance.

4. Media Restoration Details (--media-only)

The media migration script [deploy/scripts/restore-media.sh] restores media files from ~/media_backups/media/ into the MinIO scannersky-media bucket.

Timestamp Confirmation Prompt

Before importing files, the script reads the backup timestamp from ~/media_backups/media/.backup_info (or directory modification date) and prompts for confirmation:

=== MinIO Media Restoration ===
Source directory: /home/scannersking/media_backups/media
Backup Date/Time: Fri Aug 7 14:30:00 PST 2026
Target Bucket: scannersky-media
Continue restoring media backup from [Fri Aug 7 14:30:00 PST 2026]? [y/N]: y

Support for Legacy /media/ Copies
If a media folder was copied directly from an old non-containerized installation (without a .backup_info metadata file), restore-media.sh automatically reads the folder's file modification timestamp and imports all subdirectories (persons/, signatures/, profiles/, id_cards/, syllabi/) cleanly into MinIO.

MinIO Import & Access Policy

During restoration:

  1. Copies backup files into the minio container using docker cp.
  2. Runs MinIO Client (mc mirror --overwrite) to mirror all subdirectories (persons/, signatures/, profiles/, id_cards/, syllabi/) into bucket scannersky-media.
  3. Sets public download access (mc anonymous set download local/scannersky-media) so Nginx can proxy images without requiring signed URLs.

5. Custom Path Overrides

You can pass custom dump file or media directory paths on disk using DUMP_FILE and MEDIA_DIR:

# Custom SQL Dump File Location
DUMP_FILE="/mnt/external_drive/backups/db_july.sql" bash ./deploy/scripts/restore-docker.sh --db-only

# Custom Media Backup Directory Location
MEDIA_DIR="/mnt/usb/media_backup_2026" bash ./deploy/scripts/restore-docker.sh --media-only

# Combined Custom Restore
DUMP_FILE="/tmp/custom_db.sql" MEDIA_DIR="/tmp/custom_media" bash ./deploy/scripts/restore-docker.sh --all

6. Post-Restore Verification Checklist

After running any restore operation, run the production validation suite to confirm system health:

bash ./deploy/scripts/validate-production.sh

Expected Output:

=== Production validation ===
[0/6] run Django deploy check --> OK
[1/6] check services are healthy --> OK (postgres, minio, django, nginx, mcp)
[2/6] curl /health/ (200 OK) --> OK
[3/6] check static stylesheet via Nginx --> OK
[4/6] check media bucket public path --> OK
[5/6] check admin login page --> OK
[6/6] check API root --> OK
[7/7] check Docusaurus docs site --> OK
=== Validation result: 0 failure(s) ===

Deployment Script Summary

Script FilePrimary PurposeKey Default Paths
deploy/scripts/backup-docker.shGenerates DB dumps & single-instance media backup~/db_backups/postgres_dumps/, ~/media_backups/media/
deploy/scripts/restore-docker.shInteractive DB restore & unified entrypointDUMP_FILE (Interactive selection)
deploy/scripts/restore-media.shMinIO media bucket importer with date/time confirmation~/media_backups/media/
deploy/scripts/setup-minio.shMinIO bucket provisionerscannersky-media, scannersky-static
deploy/scripts/validate-production.shEnd-to-end production health validationhttp://127.0.0.1/health/