Il sintomo arriva sempre di notte, quando il job di backup parte da cron e fallisce senza rumore. Nel log vedi exit code 2, poi una riga ambigua su file mancanti o rete instabile. In hosting questo è fastidioso perché il backup sembra “quasi riuscito”, ma il restore non è affidabile.
Qui risolviamo il caso con uno script bash che automatizza un upload verso S3 compatibile usando rclone, gestisce gli errori e scrive log utili. Il punto non è solo far partire il comando. Il punto è capire perché fallisce e come evitare falsi positivi nei job ripetitivi.
Scenario concreto: backup giornaliero di un sito hosting con database esportato in file, archivio del webroot e copia su bucket remoto. Dopo un reboot del nodo o un breve problema di rete, il cron continua a lanciare il job ma il risultato resta sporco. La metrica che conta è semplice: 0 errori silenziosi per 7 giorni.
Prerequisiti
Servono pochi elementi, ma devono essere chiari.
- Una shell bash su Linux.
- rclone configurato con un remote S3 o compatibile.
- Accesso SSH al server o al pannello hosting con cron job.
- Spazio locale temporaneo per i file di backup.
- Permessi di lettura sul sito e sul dump database.
Note: se usi un pannello come Plesk o cPanel, puoi creare il cron da interfaccia. Lo script resta identico.
Warning: non lanciare subito in produzione uno script che cancella file vecchi. Prima valida log, exit code e destinazione remota con una directory di test.
Step 1: riproduci il sintomo e leggi il log giusto
Prima di correggere, devi vedere l’errore vero. Nei job ripetitivi il problema spesso non è il comando principale. È il wrapper che nasconde stderr, oppure un set -e usato male.
Parti da un test manuale con log separati. L’idea è catturare sia stdout sia stderr in un file leggibile.
mkdir -p /var/log/backup-test
/usr/local/bin/rclone copy /backup/site.tar.gz s3backup:prod/site/ \
> /var/log/backup-test/rclone.out 2> /var/log/backup-test/rclone.err
printf 'exit=%s\n' "$?"# Output:
exit=2Se il codice è 2, rclone segnala un errore non banale. Spesso trovi nel file rclone.err una riga come questa:
failed to copy: failed to open source object: no such file or directory
Oppure:
429 Too Many Requests
La differenza è importante. Nel primo caso il file sorgente manca. Nel secondo la rete o il provider remoto stanno limitando le richieste.
Step 2: crea uno script che fallisce bene
Il primo obiettivo è impedire che il backup “vada avanti” dopo un errore. Per questo usiamo opzioni bash che bloccano i casi sporchi e una funzione di log con timestamp.
#!/usr/bin/env bash
set -Eeuo pipefail
LOG_FILE="/var/log/backup-site.log"
SRC_DIR="/srv/www/example"
ARCHIVE_DIR="/backup"
RCLONE_REMOTE="s3backup:prod/site"
log() {
printf '%s %s\n' "$(date '+%F %T')" "$*" | tee -a "$LOG_FILE"
}
trap 'log "ERRORE alla riga $LINENO"' ERR
log "Avvio backup"
tar -C "$SRC_DIR" -czf "$ARCHIVE_DIR/site.tar.gz" .
log "Archivio creato"
rclone copy "$ARCHIVE_DIR/site.tar.gz" "$RCLONE_REMOTE" --log-file "$LOG_FILE" --log-level INFO
log "Upload completato"# Output:
2026-03-25 20:00:01 Avvio backup
2026-03-25 20:00:12 Archivio creato
2026-03-25 20:00:18 Upload completatoQui il punto chiave è set -Eeuo pipefail. Se tar fallisce, lo script si ferma. Se una variabile manca, lo script si ferma. Se una pipeline nasconde un errore, lo script si ferma.
Note: rclone ha log propri. Se vuoi una diagnosi più rapida, tieni un solo file di log centrale e non spargere l’output su più canali.
Step 3: aggiungi retry controllati per i problemi intermittenti
Un backup di hosting non deve fallire al primo timeout breve. Deve però fallire davvero se il problema persiste. Per questo serve un retry limitato, con attesa crescente.
Qui non usiamo un loop infinito. Usiamo tre tentativi, poi stop. È una scelta pratica per cron e per i runbook notturni.
retry_rclone() {
local tries=1
local max=3
local delay=10
while true; do
if rclone copy "$ARCHIVE_DIR/site.tar.gz" "$RCLONE_REMOTE" --retries 1 --low-level-retries 1; then
return 0
fi
if [ "$tries" -ge "$max" ]; then
return 1
fi
log "Tentativo $tries fallito, attendo ${delay}s"
sleep "$delay"
tries=$((tries + 1))
delay=$((delay * 2))
done
}# Output:
2026-03-25 20:01:01 Tentativo 1 fallito, attendo 10s
2026-03-25 20:01:21 Tentativo 2 fallito, attendo 20sQuesto pattern è utile quando il sintomo è intermittente. Un errore DNS, un picco di latenza o una limitazione temporanea del bucket non richiedono intervento manuale immediato.
Warning: non mettere retry infiniti su operazioni di scrittura. Rischi di saturare banda, storage e finestra di manutenzione.
Step 4: rendi il backup idempotente con file temporanei
Molti script falliscono perché sovrascrivono direttamente il file finale. Meglio generare un file temporaneo, validarlo e poi rinominarlo. Così eviti archivi parziali dopo un crash.
TMP_ARCHIVE="${ARCHIVE_DIR}/site.tar.gz.tmp"
FINAL_ARCHIVE="${ARCHIVE_DIR}/site.tar.gz"
rm -f "$TMP_ARCHIVE"
tar -C "$SRC_DIR" -czf "$TMP_ARCHIVE" .
if [ ! -s "$TMP_ARCHIVE" ]; then
log "Archivio vuoto"
exit 1
fi
mv -f "$TMP_ARCHIVE" "$FINAL_ARCHIVE"# Output:
2026-03-25 20:02:10 Archivio vuotoLa verifica -s evita di caricare sul bucket un file da zero byte. È una protezione semplice, ma in hosting risparmia ore di debugging quando il dump database è vuoto per un permesso sbagliato.
Step 5: integra il job in cron o nel pannello hosting
Se lavori da pannello, la strada più semplice è questa: vai in Strumenti → Attività pianificate oppure Cron Jobs, poi inserisci il comando completo dello script. Se il pannello permette il percorso assoluto, usa quello.
Nel terminale il cron resta più chiaro da verificare. Esempio:
0 3 * * * /usr/local/sbin/backup-site.sh >> /var/log/backup-site.cron 2>&1# Output:
cron avviato alle 03:00, exit=0Note: se il pannello non mostra l’uscita completa, indirizza tutto su un file. Nei backup notturni il log del cron è spesso più importante del log applicativo.
Verifica permessi e ambiente
Prima di dare per buono il job, controlla tre cose: utente, path e variabili. Molti errori di automazione sono banali ma costosi.
id
ls -ld /srv/www/example /backup
command -v rclone
# Output:
uid=1001(backup) gid=1001(backup) groups=1001(backup)
/usr/local/bin/rcloneSe il cron gira con un utente diverso dalla shell manuale, il comportamento cambia. Questo è normale. È anche la causa più comune dei backup che “funzionano a mano” e falliscono di notte.
Verifica finale
La verifica deve dirti tre cose: il file è stato creato, il file è stato caricato e il codice finale è zero. Non basta vedere una riga verde a video.
Esegui questo controllo dopo un run completo:
test -s /backup/site.tar.gz && echo OK_FILE
rclone ls "$RCLONE_REMOTE" | head
printf 'exit=%s\n' "$?"# Output:
OK_FILE
184320 site.tar.gz
exit=0Se vuoi un controllo più solido, confronta anche la dimensione locale con quella remota. Non sempre serve l’hash completo, ma serve un segnale affidabile che l’upload non sia tronco.
Un buon criterio operativo è questo: per una settimana lo script deve chiudere con exit code zero e log coerenti. Se compare un errore, deve essere leggibile in meno di un minuto.
Troubleshooting
Errore: rclone: failed to open source object: no such file or directory
Causa: il path del file sorgente non esiste oppure l’archivio viene creato in una directory diversa da quella attesa.
Fix:
ls -lah /backup
find / -name 'site.tar.gz' 2>/dev/nullSe il path è sbagliato, correggi la variabile ARCHIVE_DIR e rilancia.
Errore: 429 Too Many Requests
Causa: il provider S3 sta limitando le richieste o il job parte troppe volte in parallelo.
Fix:
pgrep -af backup-site.sh
flock -n /var/lock/backup-site.lock /usr/local/sbin/backup-site.shSe trovi esecuzioni sovrapposte, aggiungi flock nel cron.
Errore: tar: .: file changed as we read it
Causa: stai archiviando file che cambiano durante il backup, come cache o upload temporanei.
Fix:
tar --exclude='cache' --exclude='tmp' -C /srv/www/example -czf /backup/site.tar.gz .Se il sito scrive molto, escludi le directory dinamiche o ferma il writer prima del dump.
Conclusione
Il punto non è solo automatizzare il backup. Il punto è trasformare un errore intermittente in un problema diagnosticabile. Con bash robusto, log puliti e retry limitati, il job smette di mentire.
Il prossimo passo concreto è aggiungere un controllo di integrità post-upload, poi una notifica email o webhook solo in caso di fallimento. Così il backup non resta solo “eseguito”. Resta anche verificabile.
Note: se vuoi, il passo successivo naturale è un controllo giornaliero del restore su un ambiente di staging.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.