Operations Runbook
This page contains day-2 operations guidance for the ScannerSky Docker stack.
Monitoring Commands
# Check status of all containers
docker compose ps
# View live container logs
docker compose logs -f django
docker compose logs -f nginx
docker compose logs -f minio
docker compose logs -f postgres
docker compose logs -f mcp
# Inspect container health states
docker compose ps --format "table {{.Name}}\t{{.Service}}\t{{.Status}}"
Backup and Restore Operations
1. Automated Backup Workflow (deploy/scripts/backup-docker.sh)
Performs both PostgreSQL database dumping and MinIO media bucket exporting in a single execution.
# Execute containerized PostgreSQL & MinIO media backup:
bash ./deploy/scripts/backup-docker.sh
- Database Output:
~/db_backups/postgres_dumps/scannersky_YYYYMMDD_HHMMSS.sql - Media Output:
~/media_backups/media/(Single-instance overwrite) - Retention Policy: Automatically purges old SQL dumps older than 7 days.
Automated Nightly Backup Cron
Add to host crontab (crontab -e):
0 2 * * * ~/scannersky-django/deploy/scripts/backup-docker.sh >> ~/db_backups/backup.log 2>&1
2. Database & Media Restoration (deploy/scripts/restore-docker.sh)
The restore suite provides a unified entrypoint (restore-docker.sh) with three operating modes:
# 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. Default Path Resolutions & Interactive Selection
When no explicit paths are specified, the restore scripts resolve default locations automatically:
A. Database Dump Defaults (DUMP_FILE)
- Default Search Path:
~/db_backups/postgres_dumps/ - Interactive Selection: Scans
~/db_backups/postgres_dumps/, lists available SQL dump files with file sizes and modification timestamps, and prompts the operator to choose a dump file number. - Non-Interactive Mode: Automatically selects the latest valid SQL dump (
> 10 KB).
B. Media Backup Defaults (MEDIA_DIR)
- Default Search Path:
~/media_backups/media/ - Confirmation Prompt: Displays the modification date and time of the media backup (
~/media_backups/media/.backup_info) and prompts for operator confirmation (Continue restoring media backup from [TIMESTAMP]? [y/N]) before importing into MinIO.
4. Custom Path Overrides
You can pass any custom dump file or media directory path on disk using environment variables or command arguments:
# 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
5. Internal Container Execution Details
- Database Restore:
- Executes
psql -d postgresinside thepostgrescontainer. - Runs
DROP DATABASE IF EXISTS "scannersky" WITH (FORCE);to safely drop all active Django client connections. - Executes
CREATE DATABASE "scannersky";. - Pipes the SQL dump directly into
psqlinside the container.
- Executes
- Media Restore (
deploy/scripts/restore-media.sh):- Copies backup files into the
miniocontainer usingdocker cp. - Runs
mc mirror --overwriteto push all media subdirectories (persons/,signatures/,profiles/,id_cards/,syllabi/) into MinIO bucketscannersky-media. - Sets bucket policy
mc anonymous set download local/scannersky-mediaso Nginx can proxy uploaded images directly.
- Copies backup files into the
Common Issues & Fixes
1. Nginx 502 Bad Gateway
- Cause:
djangocontainer is restarting or failing healthcheck. - Fix: Check
docker compose logs django. EnsureDB_HOST=postgresand database migrations have run (docker compose exec django python manage.py migrate).
2. Unstyled Admin UI (Missing CSS/JS)
- Cause: MinIO static bucket empty or Nginx proxy rewrite issue.
- Fix: Run
docker compose exec django python manage.py collectstatic --noinput, verifydeploy/scripts/setup-minio.sh, and reload Nginx (docker compose restart nginx).
3. CSRF Verification Failed (403 Forbidden)
- Cause: Missing
Hostheader proxying or domain not inCSRF_TRUSTED_ORIGINS. - Fix: Ensure
proxy_set_header Host $host;is set in Nginx location/block.scannersky/settings.pyautomatically populatesCSRF_TRUSTED_ORIGINSfor allALLOWED_HOSTS.
4. MCP Server Import Error
- Cause: PyPI
mcp2.0.0 breaking change. - Fix: Pin
mcp>=1.0.0,<2.0.0inrequirements.txtand rebuild images (docker compose build mcp).
Recovery Checklist
- Verify Docker daemon is running (
docker compose ps). - Confirm
postgres,minio,django,nginx, andmcpservices reporthealthy. - Execute
bash ./deploy/scripts/validate-production.sh. - Verify HTTP 200 response on
/health/,/admin/,/api/, and/docs/.