Il backup che serve davvero

Un impianto che monitora casa e manda avvisi è pieno di cose che non si rifanno in un'ora: la configurazione di Home Assistant, la sessione di WhatsApp collegata, l'adozione degli access point nel controller, decine di script. Se il disco si rompe, tutto questo va rifatto. Da qui il backup notturno.

Le regole che mi sono dato: l'archivio è cifrato, perché contiene secrets.yaml, la sessione WhatsApp e altre chiavi. Viene verificato subito dopo la creazione. Se non riesce, mi avvisa. E il ripristino è scritto in un file di testo accanto agli archivi, per non doverlo ricordare a memoria nel giorno peggiore.

Cosa entra nell'archivio

Ogni notte lo script crea un solo archivio srv-home-DATA.7z con quattro cartelle dentro.

  • Home Assistant: tutta la cartella di configurazione (secrets, cartella .storage, pacchetti, dashboard, script), esclusi i database della cronologia (*.db) e i log. Sono grandi e non insostituibili: la cronologia dei sensori nel backup non c'è, e dopo un ripristino riparte da zero.
  • OpenWA: il volume dati con la sessione WhatsApp, il database e la chiave API, senza le cache di Chromium. Il contenitore viene messo in pausa per pochi secondi mentre si copia.
  • Omada: i volumi dati del controller (adozione degli access point, impostazioni). Il contenitore si ferma per circa 1-2 minuti, gli access point continuano a trasmettere, poi riparte.
  • Configurazione: il docker inspect dei contenitori, il compose di OpenWA, le cartelle degli script, la configurazione di Libre Hardware Monitor e l'esportazione in XML delle attività pianificate srv-home-*.

Nel contenitore di Omada e in quello di OpenWA si copia da un altro contenitore usa e getta (alpine) che monta il volume in sola lettura e lo comprime con tar. È il modo per leggere un volume Docker senza raggiungerlo dal disco di Windows.

Cifratura, verifica e rotazione

L'archivio è creato con 7-Zip in formato 7z, con cifratura AES-256 e cifratura anche dei nomi dei file (-mhe=on). Senza password non si vede nemmeno l'elenco di cosa contiene. Subito dopo la creazione lo script lancia 7z t, il test di integrità: un archivio corrotto viene scoperto la notte stessa, non il giorno del ripristino. Poi tiene gli ultimi sette e cancella i più vecchi.

$archive = Join-Path $Dest "srv-home-$stamp.7z"
& $SevenZip a -t7z -mx=3 -mhe=on "-p$pass" $archive "$Work\*" | Out-Null
& $SevenZip t "-p$pass" $archive | Out-Null                      # verifica di integrità

Get-ChildItem $Dest -Filter 'srv-home-*.7z' | Sort-Object LastWriteTime -Descending |
    Select-Object -Skip $Keep | ForEach-Object {
        Remove-Item $_.FullName -Force
        Log "Rimosso vecchio backup: $($_.Name)"
    }

La password la scegli durante l'installazione, con conferma e una lunghezza minima di 10 caratteri. Scrivila fuori dal mini PC: senza, i backup non si aprono. Sul PC viene salvata protetta con DPAPI (leggibile solo dal tuo utente), per far girare l'attività di notte senza chiederla. Se rifai l'installazione da zero, la password va rifatta.

Le opzioni dell'installatore sono tre: -Dest per la cartella degli archivi, -Keep per quanti tenerne (predefinito 7) e -Ora per l'orario (predefinito 03:30). Come destinazione si può usare una cartella sincronizzata con un servizio cloud: l'archivio esce già cifrato.

Se qualcosa va storto a metà

Lo script è scritto perché un errore non lasci il sistema a metà. I contenitori messi in pausa o fermati per la copia (OpenWA e Omada) vengono rimessi in funzione in un blocco finally, qualunque cosa succeda, e la cartella di lavoro temporanea viene cancellata. Ogni passo scrive una riga in backup.log con data e ora, e un errore lascia una riga che comincia con ERRORE:.

Il ripristino, scritto prima

L'installatore salva nella cartella degli archivi un file LEGGIMI-RIPRISTINO.txt. In sintesi spiega, per ogni parte:

  • Home Assistant: ferma il contenitore, copia il contenuto della cartella homeassistant nella configurazione, riavvia.
  • OpenWA: ferma il compose, ricrea il volume, ci estrae il file openwa-data.tgz con un contenitore alpine, riavvia. Se la sessione risulta scollegata, si rifà la scansione del QR dalla dashboard di OpenWA.
  • Omada: il file mounts.txt dice a quale percorso del contenitore corrisponde ogni archivio numerato. Si ricrea il contenitore con gli stessi volumi (i comandi originali sono nel docker inspect salvato), lo si ferma, si estraggono gli archivi e si riavvia. In alternativa, dal controller si può usare il ripristino con un file .cfg.
  • Attività e script: si copiano le cartelle degli script e si ricreano le attività pianificate dai file XML esportati.

Lo stato dei backup in Home Assistant

Il backup gira fuori da Home Assistant, quindi Home Assistant deve sapere com'è andato. Un secondo script, status-backup.ps1, legge backup.log e gli archivi e scrive un file status.json. Lo esegue un'attività pianificata ogni 15 minuti. Il file contiene l'esito (ok, errore, in corso, mai eseguito), l'ora dell'ultimo backup riuscito, la durata, il nome e il peso dell'ultimo archivio, quanti archivi ci sono, lo spazio libero sul disco e le ultime righe del registro.

Un backup rimasto «in corso» per più di due ore viene segnato come errore («Backup interrotto senza completare»).

Da lì nasce il pacchetto backup.yaml: i sensori di esito, ore dall'ultimo backup riuscito, dimensione, numero di archivi e spazio libero, un sensore «Backup problema» e un avviso. L'avviso parte se l'ultimo backup è fallito oppure se l'ultimo riuscito è più vecchio di 30 ore. Il testo dice l'errore, oppure «Nessun backup riuscito nelle ultime 30 ore». Il canale di consegna è quello scelto nel menu della scheda «Messaggi» (vedi la guida sui messaggi).

La scheda «Backup» del dashboard ha quattro riquadri: lo stato dei backup, i dettagli (ultimo riuscito, problema, spazio libero sul disco C), l'elenco degli archivi conservati e le ultime righe del registro.

Se il backup è la rete di sicurezza, il resto lo copre la guida sul mini PC: il controllo esterno ti dice se il PC è sparito, e l'accesso remoto serve per arrivarci.