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-backupBinary (symlink stabile verso il target di build del workspace):
/opt/obelica/infra/bin/obelica-backup -> /opt/obelica/infra/tools/target/release/obelica-backupAttenzione: 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 runOutput:
/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>&1Pipeline:
- crea snapshot locale completo;
- sincronizza lo snapshot su DigitalOcean Spaces;
- verifica il manifest remoto;
- 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 runDecifrare un file:
/opt/obelica/infra/bin/obelica backup decrypt \
/opt/obelica/backups/auto/YYYYMMDD-HHMMSS/secrets.tar.gz.enc \
/tmp/secrets.tar.gzBackup leggero della configurazione prima di modifiche infrastrutturali:
/opt/obelica/infra/bin/obelica backup configsControllare ultimo backup locale e manifest offsite:
/opt/obelica/infra/bin/obelica backup statusSincronizzare l'ultimo snapshot locale verso DigitalOcean Spaces Cold Storage:
/opt/obelica/infra/bin/obelica backup offsite-syncSincronizzare tutti gli snapshot locali esistenti verso Spaces, utile prima di una pulizia retroattiva:
/opt/obelica/infra/bin/obelica backup offsite-sync-allVerificare il manifest offsite dell'ultimo snapshot:
/opt/obelica/infra/bin/obelica backup verify-offsitePulire gli snapshot locali mantenendo solo l'ultimo, con verifica offsite per ogni snapshot rimosso:
/opt/obelica/infra/bin/obelica backup prune-local --keep 1Offsite Cold Storage
Bucket:
obelica-backups-prodEndpoint:
https://obelica-backups-prod.fra1.digitaloceanspaces.comConfigurazione secret:
/opt/obelica/secrets/backups/offsite.envPolicy:
- 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-offsiteebackup prune-local; - il bucket
obelica-backups-prode' stato creato in FRA1; - sync offsite completato per gli snapshot locali automatici presenti;
- snapshot locali storici
20260622-040001e20260623-040002caricati su Spaces prima della rimozione locale; - il motore
obelica-backupproduceconfig.tar.zst.enceforgejo-app-data.tar.zst.encrealmente 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
/tmpe poi rimosso; - il crontab esegue
offsite-sync,verify-offsiteeprune-local --keep 1solo 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 --workspaceI 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 erroriPermission denied; - imposta permessi
600su 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-statusper 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 # applicaRegole 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.zstora 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.