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:
~/apps/dicechess-trainer/data/dicechess.dbBecause 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.
Recommended: Online backup with sqlite3 .backup
Section titled “Recommended: Online backup with sqlite3 .backup”-
SSH into the Raspberry Pi
Terminal window ssh jegors@192.168.10.9 -
Go to the deployment directory
Terminal window cd ~/apps/dicechess-trainer -
Create a timestamped backup directory
Terminal window mkdir -p backupsBACKUP_TS="$(date +%Y%m%d-%H%M%S)"BACKUP_PATH="backups/dicechess-${BACKUP_TS}.db" -
Create a consistent SQLite snapshot
Terminal window sqlite3 data/dicechess.db ".backup '${BACKUP_PATH}'" -
Verify the backup exists
Terminal window ls -lh "$BACKUP_PATH"sqlite3 "$BACKUP_PATH" "PRAGMA integrity_check;"Expected integrity-check result:
ok
Copy the backup to your local machine
Section titled “Copy the backup to your local machine”Run these commands on your local machine, not on the Raspberry Pi.
mkdir -p ~/backups/dicechessscp jegors@192.168.10.9:~/apps/dicechess-trainer/backups/dicechess-YYYYMMDD-HHMMSS.db ~/backups/dicechess/mkdir -p ~/backups/dicechessrsync -avz --progress jegors@192.168.10.9:~/apps/dicechess-trainer/backups/dicechess-YYYYMMDD-HHMMSS.db ~/backups/dicechess/After copying, you can validate the local file:
sqlite3 ~/backups/dicechess/dicechess-YYYYMMDD-HHMMSS.db "PRAGMA integrity_check;"One-liner workflow
Section titled “One-liner workflow”If you want a compact flow on the Raspberry Pi:
cd ~/apps/dicechess-trainermkdir -p backupsBACKUP_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:
mise run db:backup-remoteThis wraps the GitHub CLI and transparently launches the ops-backup-stage-refresh.yaml workflow for you.
Option B: Trigger via GitHub Web UI
Section titled “Option B: Trigger via GitHub Web UI”-
Open Actions → Ops: Backup and Stage Refresh.
-
Click Run workflow and choose inputs:
retention_days(default30)run_stage_refresh(trueto restore latest backup to staging)notify_telegram(trueto send Telegram alerts)
-
Wait for
backup-productiononrpi4:- runs
sqlite3 .backup - validates with
PRAGMA integrity_check; - compresses to
.db.gz - applies retention cleanup
- runs
-
If enabled,
refresh-stagingonrpi3downloads the backup artifact and restores it to staging.
Telegram configuration
Section titled “Telegram configuration”The workflow uses two repository secrets:
TELEGRAM_BOT_TOKENTELEGRAM_CHAT_ID
Create and configure them as follows.
-
Create a bot with @BotFather (
/newbot) and copy the token. -
Send at least one message to your bot (for example
/start). -
Fetch your chat id:
Terminal window curl -s "https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates"Find
message.chat.idin the response and copy that value. -
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)
Fallback: stopped-app file copy
Section titled “Fallback: stopped-app file copy”If sqlite3 is unavailable on the Pi, stop the app first and copy the database files only while the service
is down.
cd ~/apps/dicechess-trainerdocker compose stop web db-admincp data/dicechess.db backups/dicechess-stopped-copy.dbdocker compose start web db-adminOptional: 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:
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.
Restore notes
Section titled “Restore notes”To inspect a backup locally:
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.