Su uno dei nostri server i database vengono salvati ogni ora. I backup sono cifrati con restic, un programma di backup open source, e spediti su Backblaze B2, un archivio nel cloud. Sulla carta, uno schema solido.
A giugno 2026 ha smesso di funzionare. Ce ne siamo accorti a settembre.
Cosa si era rotto
Ogni notte il comando restic forget --prune faceva pulizia dei backup vecchi. Per lavorare blocca l'archivio, e quella pulizia lo teneva bloccato per ore.
Il backup orario successivo trovava l'archivio occupato e falliva. Poi quello dopo, e quello dopo ancora. In tre mesi i tentativi falliti sono stati 7.162.
Il dettaglio peggiore è che il log scriveva comunque «OK». Chi lo apriva trovava una colonna ordinata di conferme, e nessun segno del problema.
Come l'abbiamo rifatto
- Uno script nuovo con due modalità. Quella oraria salva solo i database. Quella giornaliera salva i file dei siti e fa la pulizia dei vecchi backup, separata dal giro orario.
- Controllo dell'età dell'ultimo backup. Se l'ultima copia è troppo vecchia arriva una mail di avviso, qualunque cosa dica il log.
- Log con rotazione, cioè archiviati e ricominciati a intervalli regolari, così non crescono all'infinito e restano leggibili.
Il controllo che conta
Il cuore del lavoro è il secondo punto. Invece di chiedere allo script se è andato tutto bene, chiediamo all'archivio quando è stata fatta l'ultima copia. Quella risposta non dipende da un messaggio scritto male.
Un controllo del genere in bash sta in poche righe. Questa è una versione semplificata, che presuppone le variabili di restic (archivio e password) già impostate:
#!/bin/bash
# Avvisa se l'ultimo backup ha più di MAX_ORE ore
MAX_ORE=2
ultimo=$(restic snapshots --no-lock --latest 1 --json \
| jq -r 'sort_by(.time) | last | .time // empty')
if [ -z "$ultimo" ]; then
echo "Nessun backup trovato" | mail -s "Backup: ERRORE" [email protected]
exit 1
fi
eta=$(( ( $(date +%s) - $(date -d "$ultimo" +%s) ) / 3600 ))
if [ "$eta" -ge "$MAX_ORE" ]; then
echo "Ultimo backup di $eta ore fa ($ultimo)" \
| mail -s "Backup in ritardo" [email protected]
fi
Lo script legge la data dell'ultima copia, la confronta con l'ora attuale e scrive solo se qualcosa non va. Se l'archivio non risponde affatto, avvisa lo stesso.
E se qualcuno entra nel server?
I backup devono resistere anche a un altro rischio: un attaccante che entra nel server può provare a cancellarli.
Su un altro dei nostri server lo abbiamo chiuso così. Le chiavi con cui il server scrive sull'archivio sono in sola scrittura, e l'archivio ha un blocco di 30 giorni, l'Object Lock. Per un mese nessuno può cancellare o modificare una copia, nemmeno usando le chiavi del server.
La lezione
Un backup non controllato è un'opinione.
Il messaggio «OK» dice al massimo che uno script è arrivato in fondo. L'età dell'ultima copia dice se il backup c'è davvero, e da noi si controlla quella.
Se avete dei backup, chiedete a chi li gestisce due cose: quando è stata fatta l'ultima copia, e chi se ne accorge se smettono. Se la risposta alla seconda è «nessuno», sapete da dove cominciare.


