Obelica Docs
Backup

obelica-backup

Tool Rust per backup automatico di Obelica

Scopo

obelica-backup e' il motore Rust che esegue il backup automatico quotidiano del server. Dal 2026-06-23 viene orchestrato dal control plane Rust obelica.

Copre:

  • database applicativi (DigitalOcean managed PostgreSQL);
  • database Forgejo;
  • app-data Forgejo;
  • repository Git;
  • configurazione infrastrutturale;
  • secret.

Path

Sorgente:

/opt/obelica/infra/tools/obelica-backup

Binary (symlink stabile verso il target di build del workspace):

/opt/obelica/infra/bin/obelica-backup -> /opt/obelica/infra/tools/target/release/obelica-backup

Attenzione: i path per-crate (obelica-backup/target/release/...) sono morti con il passaggio a workspace root e possono contenere binari stale. Usare sempre i symlink in /opt/obelica/infra/bin/.

Wrapper operativo:

/opt/obelica/infra/bin/obelica backup run

Output:

/opt/obelica/backups/auto/YYYYMMDD-HHMMSS/

Schedulazione

Crontab attivo per l'utente bona:

0 4 * * * /opt/obelica/infra/bin/obelica backup run >> /opt/obelica/backups/backup-cron.log 2>&1 && /opt/obelica/infra/bin/obelica backup offsite-sync >> /opt/obelica/backups/backup-cron.log 2>&1 && /opt/obelica/infra/bin/obelica backup verify-offsite >> /opt/obelica/backups/backup-cron.log 2>&1 && /opt/obelica/infra/bin/obelica backup prune-local --keep 1 >> /opt/obelica/backups/backup-cron.log 2>&1

Pipeline:

  1. crea snapshot locale completo;
  2. sincronizza lo snapshot su DigitalOcean Spaces;
  3. verifica il manifest remoto;
  4. elimina gli snapshot locali eccedenti solo se hanno manifest offsite verificato.

Retention locale:

  • mantiene 1 snapshot completo sul droplet;
  • mantiene la cronologia su Spaces Cold Storage;
  • non elimina uno snapshot locale se manca il relativo manifest offsite.

Cifratura

I file sensibili (dump DB e secret) vengono cifrati con ChaCha20Poly1305.

La chiave simmetrica viene derivata dalla passphrase in /opt/obelica/secrets/.backup-passphrase tramite PBKDF2-HMAC-SHA256 con 100.000 iterazioni.

Ogni file cifrato contiene:

  • magic OBK1;
  • salt 16 byte;
  • sequenza di chunk con nonce 12 byte + ciphertext+tag.

La cifratura avviene in streaming per gestire file grandi (es. app-data Forgejo da circa 1.8 GiB) senza caricarli in memoria.

Artefatti cifrati:

  • databases/*.sql.gz.enc;
  • forgejo-app-data.tar.zst.enc;
  • repos.tar.zst.enc (dal 2026-07-03, prima era in chiaro);
  • config.tar.zst.enc;
  • secrets.tar.zst.enc.

Artefatti non cifrati:

  • offsite-manifest.txt (già redatto, nessun valore sensibile).

Comandi

Eseguire backup manualmente:

/opt/obelica/infra/bin/obelica backup run

Decifrare un file:

/opt/obelica/infra/bin/obelica backup decrypt \
  /opt/obelica/backups/auto/YYYYMMDD-HHMMSS/secrets.tar.gz.enc \
  /tmp/secrets.tar.gz

Backup leggero della configurazione prima di modifiche infrastrutturali:

/opt/obelica/infra/bin/obelica backup configs

Controllare ultimo backup locale e manifest offsite:

/opt/obelica/infra/bin/obelica backup status

Sincronizzare l'ultimo snapshot locale verso DigitalOcean Spaces Cold Storage:

/opt/obelica/infra/bin/obelica backup offsite-sync

Sincronizzare tutti gli snapshot locali esistenti verso Spaces, utile prima di una pulizia retroattiva:

/opt/obelica/infra/bin/obelica backup offsite-sync-all

Verificare il manifest offsite dell'ultimo snapshot:

/opt/obelica/infra/bin/obelica backup verify-offsite

Pulire gli snapshot locali mantenendo solo l'ultimo, con verifica offsite per ogni snapshot rimosso:

/opt/obelica/infra/bin/obelica backup prune-local --keep 1

Offsite Cold Storage

Bucket:

obelica-backups-prod

Endpoint:

https://obelica-backups-prod.fra1.digitaloceanspaces.com

Configurazione secret:

/opt/obelica/secrets/backups/offsite.env

Policy:

  • bucket privato;
  • storage type Cold Storage;
  • CDN disabilitata;
  • upload solo di artefatti di backup gia' cifrati dove sensibile;
  • prefisso remoto auto/<snapshot>/...;
  • manifest remoto auto/<snapshot>/offsite-manifest.txt.

Stato 2026-06-24:

  • il control plane server contiene backup status, backup offsite-sync, backup offsite-sync-all, backup verify-offsite e backup prune-local;
  • il bucket obelica-backups-prod e' stato creato in FRA1;
  • sync offsite completato per gli snapshot locali automatici presenti;
  • snapshot locali storici 20260622-040001 e 20260623-040002 caricati su Spaces prima della rimozione locale;
  • il motore obelica-backup produce config.tar.zst.enc e forgejo-app-data.tar.zst.enc realmente zstd;
  • snapshot locale mantenuto: 20260624-013111;
  • snapshot locali: 1;
  • spazio locale backup automatici: circa 3.7 GiB;
  • manifest remoto verificato in auto/20260624-013111/offsite-manifest.txt;
  • restore test controllato completato in /tmp e poi rimosso;
  • il crontab esegue offsite-sync, verify-offsite e prune-local --keep 1 solo se il backup locale termina con successo.

Build

Il repo e' un workspace Cargo (bona/obelica-server su Forgejo). Build sul host con la toolchain Rust dell'utente bona:

cd /opt/obelica/infra/tools
cargo build --release --workspace

I binari finiscono in /opt/obelica/infra/tools/target/release/ e sono raggiunti dai symlink in /opt/obelica/infra/bin/.

Note Operative

/opt/obelica/infra/bin/obelica punta alla build operativa aggiornata. La copia globale /usr/local/bin/obelica puo' restare indietro finche' non viene promossa manualmente con sudo; il cron non dipende da quella copia globale.

Aggiornamenti 2026-06-26

Risolto un fallimento del backup automatico causato da file target/ dei build Rust creati con owner root durante la compilazione in container. Il motore obelica-backup ora:

  • esclude le directory target/ dal backup della configurazione, evitando errori Permission denied;
  • imposta permessi 600 su tutti i file prodotti;
  • viene orchestrato dal wrapper /opt/obelica/infra/scripts/backup-cron-wrapper.sh, che scrive lo stato in /opt/obelica/backups/last-backup-status per il monitoraggio.

Retention offsite (lifecycle)

Dal 2026-07-03 il bucket ha una lifecycle S3 gestita dal control plane:

/opt/obelica/infra/bin/obelica backup lifecycle --show      # ispeziona
/opt/obelica/infra/bin/obelica backup lifecycle --days 90   # applica

Regole attive: expiration 90 giorni sul prefisso auto/, abort dei multipart incompleti a 7 giorni. Nota: la chiave offsite granulare non ha i permessi di configurazione bucket (giusto cosi'), quindi il comando lifecycle va eseguito con la chiave master via OBELICA_ROOT temporanea (vedi runbook della sessione 2026-07-03) — l'operazione e' comunque one-shot.

Aggiornamenti 2026-07-03

  • repos.tar.zst ora viene cifrato (repos.tar.zst.enc) come gli altri artefatti: i Git bundle contenevano codice cliente e viaggiavano in chiaro su Spaces (gap chiuso, era priorità #2 in backups/index).
  • Corretto il path del binario nel control plane: puntava al target per-crate stale invece che alla build del workspace; ora usa /opt/obelica/infra/bin/obelica-backup (symlink).
  • Creato escrow della passphrase di backup fuori dal droplet, sulla workstation (cartella secrets/ del framework locale, gitignored), verificato via hash. Senza escrow la morte del droplet rendeva irrecuperabili tutti i backup offsite.
  • Pipeline completa verificata con run manuale post-modifica.

Gap

  • Restore test completo su droplet separato eseguito il 2026-06-26; va reso ricorrente (drill periodico automatizzato).
  • Policy di retention/eliminazione remota su Spaces da definire dopo i primi giorni di esercizio.
  • La passphrase di escrow andrebbe copiata anche in un password manager, non solo sulla workstation.

On this page