Add consistent Borg database dumps
This commit is contained in:
+11
-19
@@ -1,6 +1,6 @@
|
||||
# Borg Backup Scope for KalliLabcore
|
||||
|
||||
Stand: 2026-05-04
|
||||
Stand: 2026-05-16
|
||||
|
||||
This file defines the target state for replacing Backrest with Borg in this homelab.
|
||||
|
||||
@@ -26,10 +26,10 @@ The inclusion of `/local/secrets` is intentional: Borg is expected to cover disa
|
||||
|
||||
| Service | Recovery Method | What Borg Should Capture |
|
||||
| --- | --- | --- |
|
||||
| Vaultwarden | file data | `/local/appdata/vaultwarden` |
|
||||
| Vaultwarden | SQLite dump + file data | `/local/borg-dumps`, `/local/appdata/vaultwarden` |
|
||||
| Paperless | DB dump + file data | `/local/borg-dumps`, `/local/appdata/paperless-ngx/data`, `/local/paperless/media`, `/local/paperless/export`, `/local/paperless/consume` |
|
||||
| Immich | DB dump + file data | `/local/borg-dumps`, `/local/immich/upload`, `/local/immich/external` |
|
||||
| Gitea | file data (SQLite inside `/data`) | `/local/gitea/data` |
|
||||
| Gitea | SQLite dump + file data | `/local/borg-dumps`, `/local/gitea/data` |
|
||||
| Mealie | DB dump + file data | `/local/borg-dumps`, `/local/appdata/mealie/data` |
|
||||
| Mail-archiver | shared Postgres dump + data protection keys | `/local/borg-dumps`, `/local/appdata/mailarchiver/data-protection-keys` |
|
||||
| Authelia | shared Postgres dump + config + secrets | `/local/borg-dumps`, `/local/appdata/authelia/config`, `/local/secrets` |
|
||||
@@ -39,10 +39,10 @@ The inclusion of `/local/secrets` is intentional: Borg is expected to cover disa
|
||||
| Paperless-GPT | file data | `/local/appdata/paperless-gpt` |
|
||||
| Tailscale | file data | `/local/appdata/tailscale` |
|
||||
| AdGuard | config only | `/local/appdata/adguard/conf` |
|
||||
| Borg UI | self-backup | `/local/appdata/borg-ui/data` |
|
||||
| Borg UI | SQLite dump + self-backup | `/local/borg-dumps`, `/local/appdata/borg-ui/data` |
|
||||
| Komodo | config + Mongo dump | `/local/borg-dumps`, `/local/appdata/komodo/periphery`, `/local/appdata/komodo/core` |
|
||||
| Nextcloud | raw DB path + file data | `/local/appdata/nextcloud/html`, `/local/appdata/nextcloud/postgres`, `/local/appdata/nextcloud/redis`; user data path see gap below |
|
||||
| Grafana | file data | `/local/appdata/grafana` |
|
||||
| Nextcloud | DB dump + file data | `/local/borg-dumps`, `/local/appdata/nextcloud/html`, `/local/nextcloud/data` |
|
||||
| Grafana | SQLite dump + file data | `/local/borg-dumps`, `/local/appdata/grafana` |
|
||||
| InfluxDB 3 Core | file data | `/local/appdata/influxdb3/data`, `/local/appdata/influxdb3/plugins` |
|
||||
| Hermes Agent | file data + SSH key | `/local/appdata/hermes-agent/data`, `/local/secrets/hermes_runner_id_ed25519` |
|
||||
| BentoPDF | rebuildable | no critical persistence in compose |
|
||||
@@ -51,20 +51,9 @@ The inclusion of `/local/secrets` is intentional: Borg is expected to cover disa
|
||||
|
||||
These are deviations from the standard "DB dump first, file path second" strategy. Decide deliberately, do not silently extend.
|
||||
|
||||
### Nextcloud database
|
||||
### Nextcloud
|
||||
|
||||
Recovery currently relies on the raw live DB path `/local/appdata/nextcloud/postgres`. This is inconsistent with the policy "Do not back up raw live database storage directories as the primary recovery artifact" stated below.
|
||||
|
||||
Open decision:
|
||||
|
||||
- Option A: extend `ops/borg-ui/scripts/pre-backup-dumps.sh` with a `nextcloud-postgres` dump and treat the raw path as transient.
|
||||
- Option B: accept the raw path as a documented Nextcloud-specific exception.
|
||||
|
||||
Until decided, the raw path is what Borg sees today and is the only Nextcloud DB recovery surface.
|
||||
|
||||
### Nextcloud user data path is outside the borg-ui mount set
|
||||
|
||||
`/mnt/user/documents/nextcloud-data` is not mounted into `borg-ui` in `ops/borg-ui/docker-compose.yml`. Nextcloud user files are therefore not in the current Borg scope. Resolution requires a separate Compose change (add a read-only mount) and is not silently fixed in this scope document.
|
||||
`pre-backup-dumps.sh` writes `nextcloud.dump` from `nextcloud-postgres`. Borg UI also mounts `/mnt/user/documents/nextcloud-data` read-only as `/local/nextcloud/data`, so database and user files are both inside scope after the Borg UI stack is recreated.
|
||||
|
||||
### Komodo Mongo dump
|
||||
|
||||
@@ -82,16 +71,19 @@ Until decided, the raw path is what Borg sees today and is the only Nextcloud DB
|
||||
|
||||
- `mealie`
|
||||
- `immich`
|
||||
- `nextcloud`
|
||||
|
||||
### Other Databases
|
||||
|
||||
- Komodo MongoDB
|
||||
- SQLite: `gitea`, `vaultwarden`, `uptime-kuma`, `speedtest-tracker`, `filebrowser`, `borg-ui`, `grafana`
|
||||
|
||||
## Explicitly Not Backed Up as Raw Live DB Files
|
||||
|
||||
- `/mnt/user/appdata/postgresql17`
|
||||
- `/mnt/user/appdata/mealie/postgres`
|
||||
- `/mnt/user/appdata/immich_postgres`
|
||||
- `/mnt/user/appdata/nextcloud/postgres`
|
||||
- `/mnt/user/appdata/komodo/mongo`
|
||||
- `/mnt/user/appdata/redis`
|
||||
- `/mnt/user/appdata/scrutiny/influxdb`
|
||||
|
||||
@@ -20,6 +20,7 @@ services:
|
||||
- /mnt/user/documents/scans_inbox:/local/paperless/consume:ro
|
||||
- /mnt/user/documents/paperless:/local/paperless/media:ro
|
||||
- /mnt/user/documents/paperless/export:/local/paperless/export:ro
|
||||
- /mnt/user/documents/nextcloud-data:/local/nextcloud/data:ro
|
||||
- /mnt/user/photos/immich:/local/immich/upload:ro
|
||||
- /mnt/user/photos/family_archive:/local/immich/external:ro
|
||||
- /mnt/user/services/gitea/data:/local/gitea/data:ro
|
||||
|
||||
@@ -68,6 +68,28 @@ dump_pg_globals() {
|
||||
atomic_write "$output" "$tmp"
|
||||
}
|
||||
|
||||
dump_sqlite_file() {
|
||||
source="$1"
|
||||
output="$2"
|
||||
label="$3"
|
||||
|
||||
if [ ! -f "$source" ]; then
|
||||
warn "Skipping missing SQLite database for $label: $source"
|
||||
return 0
|
||||
fi
|
||||
|
||||
tmp="$TMP_DIR/$(basename "$output").tmp"
|
||||
log "Dumping SQLite database '$label' from $source"
|
||||
rm -f "$tmp"
|
||||
sqlite3 "$source" ".backup $tmp"
|
||||
if [ "$(sqlite3 "$tmp" 'PRAGMA quick_check;')" != "ok" ]; then
|
||||
warn "SQLite quick_check failed for $label"
|
||||
rm -f "$tmp"
|
||||
return 1
|
||||
fi
|
||||
atomic_write "$output" "$tmp"
|
||||
}
|
||||
|
||||
dump_optional_pg_db() {
|
||||
container="$1"
|
||||
password="$2"
|
||||
@@ -131,6 +153,7 @@ dump_mongo_container() {
|
||||
|
||||
main() {
|
||||
need_cmd docker
|
||||
need_cmd sqlite3
|
||||
ensure_dirs
|
||||
|
||||
# Shared PostgreSQL 17
|
||||
@@ -162,6 +185,23 @@ main() {
|
||||
warn "Skipping missing container: immich_postgres"
|
||||
fi
|
||||
|
||||
if need_container "nextcloud-postgres"; then
|
||||
nextcloud_password="$(cat /mnt/user/appdata/secrets/nextcloud_postgres_password.txt)"
|
||||
dump_pg_db "nextcloud-postgres" "$nextcloud_password" "nextcloud" "nextcloud" "$LATEST_DIR/nextcloud.dump"
|
||||
else
|
||||
warn "Skipping missing container: nextcloud-postgres"
|
||||
fi
|
||||
|
||||
# SQLite databases. Use host-side sqlite3 so the dump does not depend on
|
||||
# utility packages inside application images.
|
||||
dump_sqlite_file "/mnt/user/services/gitea/data/gitea/gitea.db" "$LATEST_DIR/gitea.sqlite" "gitea"
|
||||
dump_sqlite_file "/mnt/user/appdata/vaultwarden/db.sqlite3" "$LATEST_DIR/vaultwarden.sqlite" "vaultwarden"
|
||||
dump_sqlite_file "/mnt/user/appdata/uptime-kuma/kuma.db" "$LATEST_DIR/uptime-kuma.sqlite" "uptime-kuma"
|
||||
dump_sqlite_file "/mnt/user/appdata/speedtest-tracker/config/database.sqlite" "$LATEST_DIR/speedtest-tracker.sqlite" "speedtest-tracker"
|
||||
dump_sqlite_file "/mnt/user/appdata/filebrowser/database/filebrowser.db" "$LATEST_DIR/filebrowser.sqlite" "filebrowser"
|
||||
dump_sqlite_file "/mnt/user/appdata/borg-ui/data/borg.db" "$LATEST_DIR/borg-ui.sqlite" "borg-ui"
|
||||
dump_sqlite_file "/mnt/user/appdata/grafana/grafana.db" "$LATEST_DIR/grafana.sqlite" "grafana"
|
||||
|
||||
# MongoDB
|
||||
dump_mongo_container "komodo-mongo" "$LATEST_DIR/komodo-mongo.archive.gz"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user