Corso Linux / Automatizzare backup e controlli del server con verifiche indipendenti
Per gestire un server servono sia backup ripristinabili sia controlli capaci di rilevare guasti e mancata esecuzione. Verifica separatamente creazione dell’archivio, integrità, ripristino, risposta HTTP e spazio libero, e prevedi un controllo esterno al server per accorgerti anche del suo arresto completo.
Collega la procedura già provata nel backup manuale con verifica del ripristino alla pianificazione con timer systemd. Un timer attivo non dimostra che l’ultimo archivio sia riuscito: creazione, prova di ripristino e segnalazione dei fallimenti restano verifiche distinte.
Il riferimento è una VM ordinaria Ubuntu 26.04 LTS o Rocky Linux 9, con Bash a interi a 64 bit e strumenti GNU. Container, WSL e altre versioni possono differire. Prepara console di recupero e annota le versioni seguendo la lezione sull’ambiente virtuale, in inglese.
Definire dati protetti e limiti del ripristino
Questo esempio protegge file statici ordinari modificati in modo controllato, come il contenuto del laboratorio Nginx. Configurazioni dei servizi, certificati, informazioni DNS e procedure di distribuzione vanno conservati separatamente; per un database usa il metodo di backup coerente previsto dal prodotto. Un archivio locale insegna il flusso di lavoro ma non protegge dal guasto del disco del server o dalla compromissione dello stesso account.
Scegli un’origine leggibile e una directory di backup privata, scrivibile soltanto dall’account incaricato e fuori dall’origine. Non pianificare tutto come root solo per aggirare i permessi. Per l’uso operativo definisci account dedicato, percorsi consentiti, cifratura e gestione delle chiavi, conservazione e copia su un archivio indipendente. I percorsi e i loro genitori devono essere fidati: questo piccolo script non difende da un altro soggetto capace di sostituirli durante l’esecuzione.
Creare lo script con origine e destinazione esplicite
Servono Bash, GNU tar, gzip, realpath, mktemp, sha256sum e date; per il confronto serve anche diff. Prima di creare $HOME/bin/course-backup.sh, controlla che non esista già, anche come collegamento: se esiste, conserva una copia e scegli un nome diverso aggiornando tutti i comandi e il timer. Il blocco seguente scrive uno script completo e ne controlla la sintassi, senza ancora eseguirlo.
mkdir -p "$HOME/bin" &&
cat > "$HOME/bin/course-backup.sh" <<'EOF' &&
#!/usr/bin/env bash
set -u
set -o pipefail
umask 077
if (( $# != 2 )); then
printf "Usage: %s SOURCE_DIRECTORY BACKUP_DIRECTORY\n" "$0" >&2
exit 2
fi
source_dir=$(realpath -e -- "$1") || exit 1
backup_dir=$(realpath -e -- "$2") || exit 1
[[ -d "$source_dir" && -d "$backup_dir" ]] || exit 1
[[ "$source_dir" != / ]] || { printf "Root source is not supported\n" >&2; exit 1; }
case "$backup_dir/" in
"$source_dir/"*) printf "Backup must be outside source\n" >&2; exit 1 ;;
esac
work=$(mktemp -d "$backup_dir/backup.XXXXXXXX") || exit 1
if ! tar -czf "$work/data.tar.gz" -C "$source_dir" .; then
printf "Archive failed: %s\n" "$work" >&2; exit 1
fi
if ! tar -tzf "$work/data.tar.gz" > /dev/null; then
printf "Archive listing failed\n" >&2; exit 1
fi
if ! (cd "$work" && sha256sum data.tar.gz > data.tar.gz.sha256); then
printf "Checksum creation failed\n" >&2; exit 1
fi
if ! date --iso-8601=seconds > "$work/created-at.txt"; then exit 1; fi
printf "complete\n" > "$work/COMPLETE" || exit 1
printf "Backup ready: %s\n" "$work"
EOF
bash -n "$HOME/bin/course-backup.sh"
realpath -e richiede percorsi esistenti e li risolve prima del confronto. Lo script rifiuta la radice / come origine e una destinazione uguale o interna all’origine. Ogni esecuzione crea una directory univoca; umask 077 limita i nuovi file ai permessi dell’utente su un normale filesystem Linux con permessi Unix. Verifica anche eventuali ACL e la protezione dei percorsi superiori.
La presenza di COMPLETE indica soltanto che questo script ha superato creazione, lettura dell’elenco, checksum e registrazione dell’ora. Non dimostra un ripristino riuscito, una copia fuori server né la scrittura durevole dopo un’interruzione elettrica. I tentativi falliti possono lasciare directory parziali per l’indagine: escludile dall’elenco dei punti di ripristino utilizzabili. La data è registrata, ma non c’è cancellazione automatica delle copie precedenti.
Durante l’archiviazione mantieni stabile l’origine. La creazione non è uno snapshot coerente di file che cambiano insieme e non sostituisce un backup applicativo. In assenza di opzioni di dereferenziazione, tar conserva i collegamenti simbolici come tali: il contenuto esterno a cui puntano non viene automaticamente incluso.
Provare creazione, integrità e ripristino separatamente
In una stessa sessione crea una directory di prova nuova e avvia il backup. La catena && interrompe i passi successivi quando un comando fallisce; non annulla i passi già riusciti.
lab=$(mktemp -d "$HOME/linux-ops-lab.XXXXXX") &&
mkdir "$lab/site" "$lab/backups" "$lab/restored" &&
printf "site version 1\n" > "$lab/site/index.html" &&
bash "$HOME/bin/course-backup.sh" "$lab/site" "$lab/backups" &&
find "$lab/backups" -maxdepth 2 -type f -print
Il comando stampa Backup ready: seguito dalla directory creata. Sostituisci ACTUAL_BACKUP_DIRECTORY nel blocco seguente con quel percorso completo, lasciando le virgolette. Mantieni la variabile lab della sessione e usa la directory restored ancora vuota. Ripristina solo archivi fidati e in una destinazione separata, mai sopra i dati in uso.
backup="ACTUAL_BACKUP_DIRECTORY" &&
test -f "$backup/COMPLETE" &&
(cd "$backup" && sha256sum -c data.tar.gz.sha256) &&
tar -xzf "$backup/data.tar.gz" -C "$lab/restored" &&
diff -r "$lab/site" "$lab/restored"
Il risultato atteso è: marcatore presente, data.tar.gz: OK e nessuna differenza da diff. La catena impedisce l’estrazione se il marcatore o la verifica del checksum falliscono. Un elenco GNU tar leggibile e un checksum corretto non provano il recupero del servizio: confronta i dati e prova separatamente il loro utilizzo nell’applicazione. Il checksum rileva alterazioni rispetto al digest salvato, ma non autentica una copia se un intruso può modificare sia archivio sia digest.
Controlla anche permessi, proprietari e label necessarie. Questo esempio non aggiunge opzioni specifiche per preservare tutte le ACL e gli attributi estesi: definiscile e verificane il ripristino quando servono. Ripeti integrità e ripristino dopo il trasferimento nell’archivio indipendente. Per una nuova prova usa una nuova destinazione vuota; non confondere file rimasti da una prova precedente con quelli appena estratti.
Controllare HTTP e spazio libero con criteri espliciti
Servono curl, GNU df e awk. Lo script riceve tre argomenti: URL, spazio libero minimo in KiB e percorso del filesystem da controllare. Considera sani soltanto gli stati HTTP 200–299, senza seguire automaticamente i redirect. Adatta il criterio se il servizio prevede un redirect o autenticazione: un 200 non prova che il corpo, il database o tutte le funzioni siano corretti.
Controlla prima che $HOME/bin/course-health.sh non esista già. Il blocco lo crea, ne verifica la sintassi e poi esegue il controllo di esempio; sostituisci URL e percorso con quelli del servizio e del volume effettivi prima della prova operativa.
cat > "$HOME/bin/course-health.sh" <<'EOF' &&
#!/usr/bin/env bash
set -u
set -o pipefail
if (( $# != 3 )); then
printf "Usage: %s URL MIN_FREE_KIB STORAGE_PATH\n" "$0" >&2; exit 2
fi
url=$1
minimum=$2
path=$3
[[ "$minimum" =~ ^[0-9]{1,18}$ ]] || exit 2
if ! status=$(curl -sS -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 15 "$url"); then
printf "HTTP transport failed\n" >&2; exit 1
fi
[[ "$status" =~ ^2[0-9][0-9]$ ]] || { printf "HTTP status=%s\n" "$status" >&2; exit 1; }
available=$(df -Pk -- "$path" | awk 'NR==2 {print $4}') || exit 1
[[ "$available" =~ ^[0-9]{1,18}$ ]] || exit 1
(( 10#$available >= 10#$minimum )) || { printf "Low storage: %s KiB\n" "$available" >&2; exit 1; }
printf "OK http=%s free_kib=%s\n" "$status" "$available"
EOF
bash -n "$HOME/bin/course-health.sh" &&
bash "$HOME/bin/course-health.sh" http://127.0.0.1/ 102400 "$HOME"
Il valore 102400 KiB equivale a 100 MiB: è una soglia didattica, non una raccomandazione operativa. Sceglila in base a crescita dei dati, durata dei backup e spazio richiesto dal ripristino; controlla separatamente gli inode. Il percorso deve appartenere al volume che vuoi sorvegliare: usare sempre la home può controllare il disco sbagliato se i backup risiedono altrove.
I numeri sono limitati a 1–18 cifre decimali per evitare l’overflow nel Bash a 64 bit assunto dall’esempio; 10# forza la base decimale anche con zeri iniziali. Valori negativi, decimali o troppo lunghi vengono rifiutati. Il codice usa lo spazio disponibile indicato da df -Pk, non una previsione dell’aumento dei dati. Un errore di df o un valore non interpretabile fa fallire il controllo.
I limiti di curl separano il tempo di connessione dal tempo massimo dell’intero trasferimento. I fallimenti di trasporto e gli stati non 2xx fanno uscire lo script con errore, anche se curl normalmente non considera un 404 un errore di trasporto. Per un sito Nginx basato sul nome usa l’URL del dominio effettivo o una richiesta con instradamento Host appropriato: il 200 della pagina predefinita su 127.0.0.1 non conferma il sito desiderato.
Collegare il timer e rilevare i guasti dall’esterno
Riutilizza il service e il timer utente completi della lezione sulla pianificazione collegata nell’introduzione. Nel servizio Type=oneshot imposta ExecStart=/bin/bash %h/bin/course-backup.sh ORIGINE_REALE PERCORSO_BACKUP_REALE, sostituendo i segnaposto con percorsi assoluti effettivi. Se contengono spazi, cita ogni argomento secondo la sintassi systemd; non è una riga interpretata automaticamente da una shell. Prova prima la stessa invocazione manualmente.
Dopo aver salvato le unità utente esegui systemctl --user daemon-reload, avvia manualmente il servizio e controllane stato e journal. Poi abilita il timer secondo la procedura della lezione e verifica systemctl --user list-timers --all. Scegli la frequenza in base a quante modifiche puoi permetterti di perdere; separa il controllo HTTP in un’altra unità con il proprio esito. Se deve funzionare dopo il logout, verifica anche i requisiti del gestore utente e del linger descritti nella lezione.
Controlla separatamente prossimo avvio, codice di uscita del servizio e freschezza dell’ultimo backup marcato completo. Un monitor nello stesso server si arresta insieme alla macchina: un osservatore esterno deve controllare l’URL reale e l’arrivo di un nuovo backup entro il tempo previsto. Un segnale positivo vecchio non deve continuare a essere considerato valido. Prova sia il guasto sia la mancata esecuzione e assegna a qualcuno la risposta operativa.
Se prevedi avvisi email o su un servizio di messaggistica, verifica realmente ricezione e gestione dei fallimenti del canale. Il successo della sola chiamata di invio non prova la consegna. Gli script qui mostrati restituiscono uno stato al chiamante e scrivono messaggi: non inviano automaticamente notifiche e non verificano un archivio remoto.
Sperimentare i fallimenti e ritirare il laboratorio
Modifica una sola condizione per volta: origine inesistente, destinazione dentro l’origine, risorsa HTTP inesistente oppure soglia di spazio volutamente superiore al disponibile. Controlla il codice di uscita e il messaggio, quindi ripristina il valore originale e ripeti il caso valido. Una risposta 404 dipende dalla risorsa e dal server scelti: verifica che la pagina di prova non restituisca comunque 200.
Verifica anche che un archivio alterato non superi il checksum e non venga estratto dalla catena di controllo. Non modificare l’unica copia utilizzabile: usa una copia sacrificabile per la prova. Le directory senza COMPLETE non vanno segnalate come backup riusciti.
Prima di pulire, interrompi e disabilita i timer del laboratorio e controlla che il servizio non stia ancora lavorando. Conserva le prove e i punti di recupero richiesti, poi rimuovi soltanto gli script e le directory creati per questo esercizio. In esercizio applica una politica di conservazione che protegga i punti di ripristino necessari, senza cancellare tutte le copie meno recenti quando lo spazio scarseggia.
Documentazione ufficiale
- GNU tar distribuito da Debian: creazione, elenco ed estrazione.
- GNU sha256sum: verifica dei digest salvati e GNU df: spazio disponibile e unità.
- curl: stato HTTP e limiti di tempo.
- systemd: sorgente del manuale service, da confrontare con la versione installata.
- GNU Bash: liste AND e limiti dell’aritmetica intera.




