Skip to content

Backups

Three layers of backup

Layer 1 — Hostinger snapshots (whole-VPS)

  • Managed via hPanel → Backups & Monitoring
  • Current count: 4 snapshots
  • Hostinger's standard policy: weekly automatic + manual on demand
  • These are full-disk snapshots — fastest restore path for catastrophic failure
  • Not enough on their own because they recover the whole machine, not just one database

Layer 2 — Postgres dumps

  • pg_dump per database, executed via /opt/backup.sh
  • Databases backed up: jb_brain, jb2b, geopolitics, obsidian_brain, ghrepos, gamine, vikunja
  • Output: /opt/backups/postgres/<db>_<date>.sql.gz
  • Retention: 30 days local, then pruned by cron

Layer 3 — Docker volume backups

  • /opt/backup.sh also tars named Docker volumes
  • Output: /opt/backups/volumes/<volume>_<date>.tar.gz
  • Known issue: some volume backups are empty — tracked as Vikunja #59. Do not assume volume backups are reliable until that is fixed.

Restore procedures

Each restore procedure lives in runbooks/:

What is NOT backed up

  • Build cache (intentional — regenerable)
  • Container ephemeral state
  • nginx-served static files that come from a git repo (the repo IS the backup)

Off-site copy

Off-site sync to Backblaze B2 is configured but waiting for credentials.

Infrastructure in place

Component Path Status
Sync script /opt/infrastructure/scripts/offsite-backup.sh ✅ ready
Setup guide /opt/infrastructure/scripts/setup-offsite-backup.sh ✅ ready
rclone /usr/bin/rclone v1.74.1 ✅ installed
Config template /etc/rclone/offsite.conf.template ✅ ready
Cron (/etc/cron.d/offsite-backup) daily 04:00 UTC ⏳ created by setup script

Activation (one-time, ~10 min)

  1. Create a Backblaze B2 account at backblaze.com
  2. Create bucket eureekka-backups — Private, EU-Central region
  3. Create an Application Key scoped to that bucket (not the master key)
  4. Run: bash /opt/infrastructure/scripts/setup-offsite-backup.sh

The setup script writes /etc/rclone/offsite.conf, verifies bucket access, and enables the daily cron.

What gets synced

  • Source: /var/backups/eureekka/ (postgres dumps + volume tarballs)
  • Destination: offsite-b2:eureekka-backups
  • Retention: 30 days on remote
  • Schedule: 04:00 UTC daily (after local backup at 03:00)

Tracked: Vikunja #572.

Verification

A successful backup that you cannot restore is not a backup. Once a quarter, a restore drill should be performed against a sandbox container:

bash /opt/backup-restore-test.sh

Last drill: never. This is a gap.