From 72b27b7fd258482f225d2b60b11cd149a479ddd4 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Fri, 24 Apr 2026 19:04:28 -0700 Subject: [PATCH] =?UTF-8?q?C0:=20docs=20=E2=80=94=20add=20mealie=20borg=20?= =?UTF-8?q?restore=20how-to?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Captures the procedure used to restore mealie's SQLite DB from a borgmatic archive after the post-DR wipe: extract from borg, snapshot the wiped DB, swap via a helper pod on the ReadWriteOnce PVC, fix UID 911 ownership. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/how-to/mealie/restore-from-borg.md | 157 ++++++++++++++++++++++++ docs/reference/services/mealie.md | 2 + 2 files changed, 159 insertions(+) create mode 100644 docs/how-to/mealie/restore-from-borg.md diff --git a/docs/how-to/mealie/restore-from-borg.md b/docs/how-to/mealie/restore-from-borg.md new file mode 100644 index 0000000..7ff3625 --- /dev/null +++ b/docs/how-to/mealie/restore-from-borg.md @@ -0,0 +1,157 @@ +--- +title: Restore Mealie from Borg +modified: 2026-04-24 +last-reviewed: 2026-04-24 +tags: + - how-to + - mealie + - backup +--- + +# Restore Mealie from Borg + +How to restore [[mealie]]'s SQLite database from a [[borgmatic]] archive when data has been lost (e.g. PVC wiped, accidental deletion, post-DR rebuild). + +## Prerequisites + +- SSH access to [[indri]] (where borgmatic runs and stores k8s SQLite dumps) +- Mealie deployment present in the cluster (the PVC `mealie-data` exists in namespace `mealie`) +- Know which borg archive predates the data loss + +## Procedure + +### 1. Identify a Pre-Loss Archive + +List archives and pick one before the incident: + +```bash +ssh indri 'BORG_PASSCOMMAND="cat /Users/erichblume/.borg/config.yaml" \ + /opt/homebrew/bin/borg list /Volumes/backups/borg | tail -30' +``` + +Compare dump sizes across archives if you're unsure when the loss happened — the daily borgmatic run captures `/Users/erichblume/.local/share/borgmatic/k8s-dumps/mealie.db`. A sudden drop in size signals the wipe: + +```bash +ssh indri 'bash -c "BORG_PASSCOMMAND=\"cat /Users/erichblume/.borg/config.yaml\" \ + /opt/homebrew/bin/borg list /Volumes/backups/borg:: \ + --pattern=+Users/erichblume/.local/share/borgmatic/k8s-dumps/mealie.db"' +``` + +### 2. Extract the Pre-Loss Dump + +```bash +ssh indri 'mkdir -p ~/tmp/mealie-restore && cd ~/tmp/mealie-restore && \ + BORG_PASSCOMMAND="cat /Users/erichblume/.borg/config.yaml" \ + /opt/homebrew/bin/borg extract /Volumes/backups/borg:: \ + Users/erichblume/.local/share/borgmatic/k8s-dumps/mealie.db' +``` + +The file lands at `~/tmp/mealie-restore/Users/erichblume/.local/share/borgmatic/k8s-dumps/mealie.db` (borg preserves the full path). + +### 3. Verify the Extracted DB + +```bash +ssh indri 'sqlite3 ~/tmp/mealie-restore/Users/erichblume/.local/share/borgmatic/k8s-dumps/mealie.db \ + "PRAGMA integrity_check; SELECT COUNT(*) FROM recipes; SELECT COUNT(*) FROM users;"' +``` + +Expect `ok` and non-zero recipe/user counts. + +### 4. Snapshot the Current (Wiped) DB + +Belt and suspenders — keep a copy of the live DB before overwriting, in case the restore goes wrong: + +```bash +ssh indri 'bash -c "kubectl --context=minikube -n mealie exec deploy/mealie -- \ + python3 -c \"import sqlite3; sqlite3.connect(\\\"/app/data/mealie.db\\\").backup(sqlite3.connect(\\\"/tmp/wiped-mealie.db\\\"))\" && \ + POD=\$(kubectl --context=minikube -n mealie get pod -l app=mealie -o jsonpath=\"{.items[0].metadata.name}\") && \ + kubectl --context=minikube cp mealie/\$POD:/tmp/wiped-mealie.db /Users/erichblume/tmp/mealie-restore/wiped-mealie.db"' +``` + +### 5. Scale Mealie Down + +The PVC is `ReadWriteOnce`, so the helper pod can't mount it while mealie is running: + +```bash +ssh indri 'kubectl --context=minikube -n mealie scale deploy/mealie --replicas=0 && \ + kubectl --context=minikube -n mealie wait --for=delete pod -l app=mealie --timeout=60s' +``` + +### 6. Start a Helper Pod on the PVC + +```bash +ssh indri 'bash -c "cat > /tmp/mealie-helper.yaml <