Skip to content

Backup Production Database

The production deployment stores SQLite data on the Raspberry Pi host in the bind-mounted data/ directory.

For example, on the current Pi setup:

Terminal window
~/apps/dicechess-trainer/data/dicechess.db

Because the app runs SQLite in WAL mode, the safest online backup method is to use SQLite’s built-in .backup command. This creates a consistent snapshot even while the app is running.

Section titled “Recommended: Online backup with sqlite3 .backup”
  1. SSH into the Raspberry Pi

    Terminal window
    ssh jegors@192.168.10.9
  2. Go to the deployment directory

    Terminal window
    cd ~/apps/dicechess-trainer
  3. Create a timestamped backup directory

    Terminal window
    mkdir -p backups
    BACKUP_TS="$(date +%Y%m%d-%H%M%S)"
    BACKUP_PATH="backups/dicechess-${BACKUP_TS}.db"
  4. Create a consistent SQLite snapshot

    Terminal window
    sqlite3 data/dicechess.db ".backup '${BACKUP_PATH}'"
  5. Verify the backup exists

    Terminal window
    ls -lh "$BACKUP_PATH"
    sqlite3 "$BACKUP_PATH" "PRAGMA integrity_check;"

    Expected integrity-check result:

    ok

Run these commands on your local machine, not on the Raspberry Pi.

Terminal window
mkdir -p ~/backups/dicechess
scp jegors@192.168.10.9:~/apps/dicechess-trainer/backups/dicechess-YYYYMMDD-HHMMSS.db ~/backups/dicechess/

After copying, you can validate the local file:

Terminal window
sqlite3 ~/backups/dicechess/dicechess-YYYYMMDD-HHMMSS.db "PRAGMA integrity_check;"

If you want a compact flow on the Raspberry Pi:

Terminal window
cd ~/apps/dicechess-trainer
mkdir -p backups
BACKUP_TS="$(date +%Y%m%d-%H%M%S)"
BACKUP_PATH="backups/dicechess-${BACKUP_TS}.db"
sqlite3 data/dicechess.db ".backup '${BACKUP_PATH}'"
sqlite3 "$BACKUP_PATH" "PRAGMA integrity_check;"
echo "$BACKUP_PATH"

Then copy the printed file path from your local machine with scp or rsync.

Manual backup + staging refresh via GitHub Actions

Section titled “Manual backup + staging refresh via GitHub Actions”

Use the workflow .github/workflows/ops-backup-stage-refresh.yaml when you want a single-button run from GitHub Actions.

Current mode is manual only (workflow_dispatch). You can trigger it via the GitHub UI or straight from your local terminal.

Option A: Trigger from local machine (via mise)

Section titled “Option A: Trigger from local machine (via mise)”

If you have configured mise, the easiest way is to run our pre-configured task:

Terminal window
mise run db:backup-remote

This wraps the GitHub CLI and transparently launches the ops-backup-stage-refresh.yaml workflow for you.

  1. Open Actions → Ops: Backup and Stage Refresh.

  2. Click Run workflow and choose inputs:

    • retention_days (default 30)
    • run_stage_refresh (true to restore latest backup to staging)
    • notify_telegram (true to send Telegram alerts)
  3. Wait for backup-production on rpi4:

    • runs sqlite3 .backup
    • validates with PRAGMA integrity_check;
    • compresses to .db.gz
    • applies retention cleanup
  4. If enabled, refresh-staging on rpi3 downloads the backup artifact and restores it to staging.

The workflow uses two repository secrets:

  • TELEGRAM_BOT_TOKEN
  • TELEGRAM_CHAT_ID

Create and configure them as follows.

  1. Create a bot with @BotFather (/newbot) and copy the token.

  2. Send at least one message to your bot (for example /start).

  3. Fetch your chat id:

    Terminal window
    curl -s "https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates"

    Find message.chat.id in the response and copy that value.

  4. In GitHub, open Settings → Secrets and variables → Actions → New repository secret and add:

    • TELEGRAM_BOT_TOKEN=<token from BotFather>
    • TELEGRAM_CHAT_ID=<chat id from getUpdates>

If notify_telegram=true and secrets are configured, the workflow sends success/failure messages for:

  • production backup result
  • staging refresh result (when enabled)

If sqlite3 is unavailable on the Pi, stop the app first and copy the database files only while the service is down.

Terminal window
cd ~/apps/dicechess-trainer
docker compose stop web db-admin
cp data/dicechess.db backups/dicechess-stopped-copy.db
docker compose start web db-admin

Optional: copy the raw live files for forensic inspection

Section titled “Optional: copy the raw live files for forensic inspection”

If you specifically want the raw live SQLite files, copy all three files together:

Terminal window
scp jegors@192.168.10.9:~/apps/dicechess-trainer/data/dicechess.db* ~/backups/dicechess/raw/

This is useful for low-level inspection, but it is not the preferred backup format for restore workflows.

To inspect a backup locally:

Terminal window
sqlite3 ~/backups/dicechess/dicechess-YYYYMMDD-HHMMSS.db ".tables"

To replace the production database from a backup, stop the app first and keep a copy of the current data/ directory before overwriting anything.