Commit Graph
23 Commits
Author SHA1 Message Date
kevin.bataille d467929f91 update mariadb script file 2026-08-31 00:48:16 +01:00
kevin.bataille b0a72d1190 Update nexusvoice config 2026-08-31 00:38:12 +01:00
kevin.bataille 4975bd1bda Update configs to match real environment 2026-08-31 00:27:16 +01:00
kevin.batailleandClaude Sonnet 4.6 f3cf24a41c docs: update README and RUNBOOK for multi-deployment config
- README: remove hardcoded srv paths; add configs/ to components table;
  document BACKUP_CONF usage for multi-server setups; note DB_CONTAINER=
  makes docker optional
- RUNBOOK: generalize §1 setup to use config variables (source config,
  use $REPO / $BORG_PASSPHRASE_FILE / etc. instead of hardcoded paths);
  §4 day-2 ops now shows source-config pattern before direct borg commands;
  §5 recovery notes BACKUP_CONF for restore.sh; §6 drill uses config vars

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3rQSEidP6Y61kaCtxjVV1
2026-08-30 23:50:38 +01:00
kevin.batailleandClaude Sonnet 4.6 74390b78af feat: extract deployment config into configs/ for multi-server reuse
Both borg-backup.sh and restore.sh now source a config file instead of
hardcoding paths and container names. Default is backup.conf next to the
script; override with BACKUP_CONF=/path/to/other.conf.

- configs/srv.conf     — current server (unchanged behaviour)
- configs/nexusvoice.conf — nexusvoice server (/home/acid/nexusvoice,
                            separate Scaleway path par-backup-1/nexusvoice)
- DB steps in borg-backup.sh are now guarded on [[ -n "$DB_CONTAINER" ]]
  so a config with DB_CONTAINER="" skips the dump entirely
- RUNBOOK.md §2 documents single and multi-deployment patterns

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A3rQSEidP6Y61kaCtxjVV1
2026-08-30 23:45:10 +01:00
kevin.batailleandClaude Sonnet 5 bfafb09ee6 fix: also exclude logs/ (plural) directories from the archive
Some sites use logs/ instead of log/ (e.g. webscroll.fr/logs/nginx/) -
the previous re:/log/ pattern didn't match the plural, so those files
kept showing up as modified every backup.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 23:06:32 +02:00
kevin.batailleandClaude Sonnet 5 cd17727ff9 fix: make rclone sync more resilient to Scaleway throttling
Offsite sync hit 17 fatal IO errors deleting stale segment files after a
large one-off prune batch (from the recent log/-exclude change), and
rclone's default behavior is to bail immediately on delete errors rather
than retry. Lower concurrency (--transfers 8->4, --checkers 16->8) to
reduce rate-limit pressure, and make retries explicit (--retries 5,
--retries-sleep 10s, --low-level-retries 20) instead of relying on
defaults.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 22:56:50 +02:00
kevin.batailleandClaude Sonnet 5 682ba9d64d feat: exclude per-site log/ directories from the archive
nginx access/error logs (and any other per-site log/ dir) change on
every request, so they showed up as modified in every single backup -
pure noise, no recovery value. Exclude any path containing a log/
directory (re:/log/) from borg create.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:46:35 +02:00
kevin.batailleandClaude Sonnet 5 511c95063d fix: replace undefined log() calls with echo in dump_db.sh
dump_users_and_grants() called log(), which dump_db.sh never defines
(only die()/warn() exist) - every real run printed "log: command not
found" on stderr while still completing successfully. Use echo, matching
the rest of the script's style.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:37:56 +02:00
kevin.batailleandClaude Sonnet 5 dc414de14e docs: add README, note repo is unencrypted by deliberate choice
CLAUDE.md previously said the repo was encrypted, which was true when
written but no longer matches this deployment - the operator chose to
stay unencrypted, so the recurring "not encrypted" warning is expected
behavior, not something to fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:35:54 +02:00
kevin.batailleandClaude Sonnet 5 dd4fd8cb9c fix: point dump_db.sh at its /opt/backup-agent deploy path, remove healthcheck
dump_db.sh no longer lives under $TARGET, so its own default dump
directory (relative to wherever the script is) would land outside the
backed-up tree. Pin DUMP_SCRIPT to /opt/backup-agent/dump_db.sh and
export DUMP_DIR explicitly so dumps still land in $TARGET/mariadb/dump
regardless of where the script itself is deployed.

Also drop the healthcheck integration (HEALTHCHECK_URL, send_healthcheck,
curl requirement) from borg-backup.sh per request - no monitoring hook
wanted for now.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 21:30:17 +02:00
kevin.bataille b8564703bc Use root account for database 2026-07-25 21:26:10 +02:00
kevin.bataille 88696d6e30 Update chmod 2026-07-25 21:25:05 +02:00
kevin.bataille e40802deeb No more healthcheck 2026-07-25 21:23:17 +02:00
kevin.bataille 86c7731d0c Ignore files, remove old and add CLAUDE.md 2026-07-25 21:16:30 +02:00
kevin.batailleandClaude Sonnet 5 592ef45bab fix: start mariadb before restoring DBs in cmd_full, add lock/preflight
Final review of the restore.sh branch found cmd_full restored every
database via `docker exec` before starting the container, which fails
immediately in the exact scenario full restore exists for (a freshly
rebuilt, stopped container). Reorders to extract -> start container ->
restore DBs.

Also, while touching cmd_full:
- Extract directly into place (cd / && borg extract) instead of staging
  a full copy under /tmp then cp -a'ing it into $TARGET - halves disk
  usage and restore time.
- Replace `rm -rf "$TARGET"/*` with `find "$TARGET" -mindepth 1 -delete`
  so dotfiles don't survive a --force wipe.
- Add acquire_lock() (shares borg-backup.sh's lockfile so a restore and
  the nightly backup cron can't run concurrently) and preflight()
  (passphrase file readable, repo reachable) before any real work in
  full/db/file.

Test isolation: mock borg/docker/mysql/mariadb consistently via a
BASH_ENV shim (previously only db-mode's test worked around PATH
shadowing by a real docker binary; every mocked test needed it, and a
missing `flock` mock broke everything once acquire_lock was added,
since flock(1) doesn't exist on macOS). Tests also isolate LOCKFILE and
BORG_PASSPHRASE_FILE to throwaway paths.

RUNBOOK.md: fix the quarterly drill command (borg extract has no
--destination flag, and needs `borg list --short` for a bare archive
name), reword the full-restore --force comment which read backwards,
and document the MYSQL_ROOT_PASSWORD/RESTORE_LOGDIR env overrides and
where restore logs land.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-25 19:42:56 +02:00
kevin.bataille 8d7a603615 docs: add operational runbook for backup and recovery 2026-07-25 19:27:34 +02:00
kevin.bataille 4be1372e4d feat: add full disaster-recovery mode to restore.sh
Adds container_running/container_health/wait_for_container/start_db
helpers and cmd_full(), plus tests. Fixed a delimiter bug in the two
new tests' sed scripts (the literal `${TARGET#/}` replacement text
collided with `#` as the sed delimiter) and relaxed the dry-run
no-external-calls assertion to allow the legitimate borg-list call
from resolve_archive(), mirroring the existing db dry-run test.
2026-07-25 19:23:27 +02:00
kevin.bataille 5d547f04ec feat: add single-database restore mode to restore.sh 2026-07-25 19:16:13 +02:00
kevin.bataille ea361904ba feat: add non-destructive file-restore mode to restore.sh 2026-07-25 19:01:33 +02:00
kevin.bataille 769eeea2b9 feat: add archive listing and resolution to restore.sh 2026-07-25 18:57:21 +02:00
kevin.bataille 49ed87b46b feat: add restore.sh scaffold with arg parsing and usage 2026-07-25 18:54:01 +02:00
kevin.bataille d6f30c506e chore: initial import of backup scripts and design docs
Existing borg-backup.sh/dump_db.sh, old/ reference scripts, and the
brainstormed design spec for restore tooling + runbook.
2026-07-25 18:51:38 +02:00