Strategia di backup per server root che tiene quando serve
La regola 3-2-1 su un singolo server root, restic e Borg con esempi, conservazione e cifratura. E il passo che quasi tutti saltano: mettere davvero alla prova il ripristino.
La checklist per i primi 30 minuti si chiude con un archivio tar di /etc e con la constatazione che quello non è ancora un backup, ma una copia sullo stesso disco. Questo articolo riparte da lì: come farne una strategia che sopravvive a una perdita totale.
La frase attorno a cui ruota tutto: un backup da cui non è mai stato ripristinato nulla non è un backup, è una speranza. Tutto il resto serve a trasformare quella speranza in un'affermazione verificata.
Tutti i comandi girano come root. Se lavori come utente normale, anteponi sudo a ogni comando. I sistemi di riferimento sono Debian 13 (trixie), Debian 12 (bookworm), Ubuntu 24.04 LTS e Ubuntu 22.04 LTS. Dove i quattro si comportano in modo diverso, lo trovi indicato.
Prima di cambiare qualcosa: la via di ritorno
Il backup in sé raramente si rompe. Pericolose sono le manovre che gli stanno intorno: un ripristino che scrive sopra il sistema in esecuzione, un repository che riempie il disco di sistema, file di chiave che sostituiscono il tuo stesso accesso. Quattro punti da sistemare prima.
1. Conosci l'accesso alla console prima di averne bisogno
Sui server root KVM e sui server dedicati di KernelHost la console VNC la raggiungi nell'area clienti. Non dipende dallo stack di rete del sistema guest e risponde anche quando SSH tace. È questa la via di salvataggio se un ripristino ha scritto una vecchia sshd_config o una vecchia authorized_keys sopra quella attuale. Accedi almeno una volta da lì prima che serva davvero e verifica di conoscere la password di root.
2. Il primo ripristino non va mai direttamente in /
Il primo ripristino finisce sempre in una directory vuota, per esempio /var/tmp/restore-test. Da lì confronti e ricopi indietro solo quello che serve. Un ripristino diretto in / sovrascrive anche i file che dal backup in poi sono stati modificati per un buon motivo.
3. Tieni aperta una seconda sessione
Finché lavori sulle chiavi SSH o sulla authorized_keys della destinazione, vale la stessa regola della configurazione di un firewall: lascia aperto un secondo terminale con la connessione già stabilita e chiudilo solo quando una connessione nuova funziona.
4. Controlla lo spazio prima che il repository cresca
df -h /
df -i /
La seconda riga la dimenticano quasi tutti: un filesystem si riempie anche quando restano liberi diversi gigabyte, cioè quando finiscono gli inode. Un repository locale che riempie il disco di sistema è uno dei guasti autoinflitti più frequenti. Per questo qui la destinazione sta fuori dal server fin dall'inizio.
La regola 3-2-1 applicata a un singolo server
- Tre copie. I dati in produzione sono già la prima copia. Servono quindi due backup, non uno.
- Due supporti diversi. Due directory sullo stesso disco sono un supporto solo, e due dischi nello stesso RAID pure: un
rmdato per sbaglio li colpisce entrambi. Il RAID protegge dal guasto di un disco e da nient'altro. - Una copia fuori sede. Non lo stesso server, non lo stesso account di gestione, possibilmente nemmeno la stessa sede.
Servono due integrazioni. Primo: una copia deve stare dove il server stesso non può cancellarla, perché chi prende il controllo del tuo server trova lì le credenziali per la destinazione. Secondo: una copia conta soltanto quando è stata verificata. Un'immagine del sistema nella stessa area clienti è comoda, ma come copia fuori sede non vale.
Fissa inoltre due numeri: quante ore di perdita dati puoi accettare (questo determina l'intervallo tra due esecuzioni) e quanto può durare il ripristino (questo decide se serve anche un'immagine aggiuntiva).
Che cosa va nel backup e che cosa no
L'errore più frequente non è salvare troppo poco, è salvare tutto. Chi salva l'intera / senza esclusioni si porta dietro cache dei pacchetti, file temporanei e swap.
| Che cosa | Posizione tipica | Metodo | Perché |
|---|---|---|---|
| Configurazione | /etc | Backup dei file | Ricostruirla a mano costa giorni |
| Selezione dei pacchetti | File di testo, vedi sotto | Backup dei file | Rende riproducibile la ricostruzione |
| Dati di produzione | /var/www, /srv, /home | Backup dei file | Non si recuperano da nessun'altra parte |
| Database | /var/lib/mysql | Dump invece della copia dei file | A servizio acceso le copie dei file sono incoerenti |
| Certificati | /etc/letsencrypt | Backup dei file | Chiave dell'account e limiti di emissione della CA |
| Container | File Compose e volumi | Backup dei file | Le immagini si riscaricano, i volumi no |
| Da non salvare | /proc, /sys, /dev, /run, /tmp | escludere | Interfacce del kernel senza contenuto su disco |
| Da non salvare | /var/cache, swap | escludere | Si rigenerano in qualsiasi momento |
apt-mark showmanual > /root/lista-pacchetti.txt
dpkg --get-selections > /root/selezione-pacchetti.txt
wc -l /root/lista-pacchetti.txt /root/selezione-pacchetti.txt
apt-mark showmanual elenca soltanto i pacchetti installati di proposito, senza le dipendenze trascinate dietro: è la lista breve che ti serve quando ricostruisci il server.
File, database, immagine: tre metodi che non si sostituiscono a vicenda
| Metodo | Protegge bene da | Non protegge da | Trappola tipica |
|---|---|---|---|
| Backup dei file | Cancellazioni, singoli file danneggiati, perdita del server | Incoerenza dei database aperti | File di database copiati a servizio acceso |
| Backup del database (dump) | Incoerenza, ritorno a uno stato pulito | Tutto quello che sta fuori dal database | Dump interrotto il cui file sembra utilizzabile |
| Immagine del sistema | Guasto totale, tempi di ripristino brevi | Cancellazioni notate in ritardo, perdita dell'account | Pochi stati conservati, tutti nello stesso account |
Ne deriva un ordine, non una scelta. Prima il server di database scrive un dump, poi parte il backup dei file, e la directory dei dati resta esclusa. Una copia dei file di /var/lib/mysql a servizio acceso cattura tabelle diverse in momenti diversi. Se poi quella copia si riesca a ripristinare, lo scopri nel momento peggiore.
File delle credenziali, permessi e insidie del dump li tratta Backup automatico dei database MySQL e MariaDB. Quello che conta è il punto di consegna: i dump finiscono in /var/backups/db, restano lì uno o due giorni, e la conservazione la gestisce il repository. PostgreSQL lo salvi con pg_dumpall come utente postgres.
restic oppure Borg
Entrambi spezzano i file in blocchi, memorizzano una sola volta i blocchi uguali, cifrano e conservano stati versionati. Entrambi sono pacchettizzati su tutte e quattro le distribuzioni. La differenza che decide davvero sta nell'ultima riga.
| Caratteristica | restic | Borg |
|---|---|---|
| Pacchetto | restic | borgbackup, comando borg |
| Cifratura | sempre attiva | a scelta, ha senso repokey oppure keyfile |
| Liberare spazio | forget con --prune | prune, poi compact |
| Protezione dalle cancellazioni fatte dal server | server REST oppure object storage con versionamento | borg serve --append-only |
| Requisito sulla destinazione | basta un accesso SFTP | Borg deve essere installato sulla destinazione |
Su uno storage dove non puoi installare nulla, Borg è fuori gioco. Se invece hai un secondo server Linux sotto la tua gestione, la modalità append-only gioca a favore di Borg.
Configurazione con restic
apt update
apt install -y restic
restic version
Controlla l'output prima di creare un repository: le quattro distribuzioni forniscono versioni molto diverse tra loro, e un repository creato da una versione recente non è detto che si apra con una più vecchia.
Accesso alla destinazione
Qui la destinazione è un secondo server raggiunto via SSH. La chiave appartiene a root, perché solo root può leggere tutti i file da salvare:
ssh-keygen -t ed25519 -N '' -f /root/.ssh/id_ed25519_backup -C 'backup srv01'
ssh-copy-id -i /root/.ssh/id_ed25519_backup.pub backup@203.0.113.50
cat > /root/.ssh/config <<'EOF'
Host destinazione-backup
HostName 203.0.113.50
User backup
IdentityFile /root/.ssh/id_ed25519_backup
BatchMode yes
EOF
chmod 600 /root/.ssh/config
Verifica: ssh destinazione-backup true deve concludersi senza output e senza domande. La primissima connessione chiede conferma della chiave host: rispondi adesso e non più tardi, dentro un servizio che non può aspettare nessuno.
Password e repository
install -d -m 700 /etc/restic
head -c 32 /dev/urandom | base64 | tr -d '\n' > /etc/restic/repo.pass
chmod 600 /etc/restic/repo.pass
cat > /etc/restic/env <<'EOF'
RESTIC_REPOSITORY=sftp:destinazione-backup:/srv/backup/srv01
RESTIC_PASSWORD_FILE=/etc/restic/repo.pass
EOF
chmod 600 /etc/restic/env
Questo file va bene sia per la shell sia per systemd. Nella shell:
set -a; . /etc/restic/env; set +a
restic init
Verifica: restic cat config stampa una breve struttura JSON con l'identificativo del repository. Se compare la domanda Is there a repository at the following location?, il percorso è sbagliato oppure restic init non è mai stato eseguito.
La prima esecuzione
cat > /etc/restic/excludes.txt <<'EOF'
/proc
/sys
/dev
/run
/tmp
/var/tmp
/var/cache
/var/lib/apt/lists
/var/lib/mysql
/swapfile
EOF
restic backup / --one-file-system --exclude-file=/etc/restic/excludes.txt --exclude-caches --tag system
--one-file-system tiene il backup sul filesystem di root e non si porta dietro le unità di rete montate. --exclude-caches salta le directory che si sono contrassegnate da sole come cache. L'esclusione di /var/lib/mysql è la messa in pratica della sezione precedente.
Verifica: l'esecuzione termina con una riga del tipo snapshot 0a1b2c3d saved. Poi:
restic snapshots
restic stats latest
Nell'elenco compaiono data e ora, nome della macchina e percorsi. Se restic stats latest mostra una dimensione inaspettatamente piccola, c'è un'esclusione che taglia troppo.
La stessa cosa con Borg
apt install -y borgbackup
borg --version
export BORG_REPO='ssh://backup@203.0.113.50/./srv01'
borg init --encryption=repokey-blake2
borg create --stats --compression zstd ::'system-{now}' /etc /var/www /home /var/backups
borg list
borg info
Tutte e quattro le distribuzioni forniscono una versione della serie 1.x. Borg deve essere presente su entrambi i lati, e la versione sulla destinazione non dovrebbe essere più vecchia di quella sul server. Tieni un repository separato per ogni server: così eviti di dover limitare la pulizia agli archivi di quel preciso server e puoi usare chiavi di accesso distinte.
Verifica: borg list mostra l'archivio con la marca temporale, borg info la dimensione prima e dopo la deduplicazione.
Conservazione: più lunga di quanto quasi tutti prevedano
La durata di conservazione non dipende da quanto a lungo vuoi tenere i dati, ma da quanto tempo passa prima che un danno si noti. Una directory cancellata te ne accorgi lo stesso giorno, una tabella corrotta spesso solo settimane dopo. Chi conserva sette giorni si ritrova con sette giorni di backup del danno.
| Tipo di dati | Proposta | Motivo |
|---|---|---|
| Dump dei database | 7 giornalieri, 4 settimanali, 6 mensili | I danneggiamenti silenziosi si notano tardi |
| Configurazione | 30 giornalieri, 12 mensili | Ricostruire quando è cambiato che cosa |
| Dati di produzione | 30 giornalieri, 6 mensili | Un file cancellato raramente manca subito |
| File di log | il minimo accettabile | Ingombranti, quasi mai serviti in un ripristino |
restic forget --dry-run --keep-daily 7 --keep-weekly 4 --keep-monthly 6
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
L'esecuzione di prova mostra quali stati sparirebbero. Senza --prune spariscono solo i riferimenti, mentre lo spazio resta occupato. In Borg dalla 1.2 la cosa avviene in due passaggi, e il secondo comando dimenticato spiega la maggior parte dei repository che non vogliono rimpicciolirsi:
borg prune --list --dry-run --keep-daily=7 --keep-weekly=4 --keep-monthly=6
borg prune --list --keep-daily=7 --keep-weekly=4 --keep-monthly=6
borg compact
Verifica: restic snapshots oppure borg list mostra lo scaglionamento previsto, e lo spazio occupato sulla destinazione cala.
Cifratura e la chiave che poi non ha più nessuno
Entrambi gli strumenti cifrano prima che i dati lascino il server. La destinazione vede soltanto blocchi illeggibili, ed è questo a rendere accettabile uno storage di terzi. Il prezzo è chiaro: senza password o senza chiave i dati sono persi per sempre. Non esiste nessuna backdoor.
Ne discendono due regole. Primo: la password va tenuta anche in un secondo posto, di solito in un gestore di password. Una password che sta soltanto in /etc/restic/repo.pass sparisce insieme al server, e con lei il backup. Secondo: con Borg in modalità repokey esporta la chiave e conservala fuori, perché in quel caso risiede dentro il repository stesso:
borg key export ::
Verifica: esegui restic snapshots su un'altra macchina, usando la password presa dal gestore di password. Una password che non hai mai usato da un'altra postazione resta non confermata.
Proteggere la destinazione dalle cancellazioni
Un attaccante con i permessi di root ha accesso anche alla password depositata e alla chiave per la destinazione. Può quindi cancellare il backup prima di cifrare i dati in produzione. Serve perciò un supporto che accetti stati nuovi ma non permetta cancellazioni. Con Borg lo imposti nella authorized_keys dell'utente di backup sulla destinazione:
command="borg serve --append-only --restrict-to-path /srv/backup/srv01",restrict ssh-ed25519 AAAA... backup srv01
Da quel momento la chiave accetta soltanto backup, e soltanto dentro quel percorso. Mettiti in conto che qui un prune arriva in fondo senza errori ma non libera spazio, perché la cancellazione sulla destinazione non viene eseguita. La pulizia la fai lì, dove il server non ha accesso. Con restic questo ruolo lo assumono il server REST in modalità append-only oppure un object storage con versionamento. Un semplice accesso SFTP non basta.
Automatizzare con un timer systemd
Un timer è preferibile a un cron job, perché scrive l'output nel journal, recupera le esecuzioni saltate e può distribuire nel tempo l'orario di avvio. Sulla struttura delle unit: Creare un servizio systemd personalizzato.
cat > /etc/systemd/system/backup.service <<'EOF'
[Unit]
Description=Backup giornaliero con restic
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
EnvironmentFile=/etc/restic/env
Nice=10
IOSchedulingClass=idle
ExecStart=/usr/bin/restic backup / --one-file-system --exclude-file=/etc/restic/excludes.txt --exclude-caches --tag system
ExecStart=/usr/bin/restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
EOF
cat > /etc/systemd/system/backup.timer <<'EOF'
[Unit]
Description=Avvia il backup giornaliero
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=1800
Persistent=true
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now backup.timer
systemd-analyze calendar '*-*-* 02:30:00'
Più righe ExecStart in una unit oneshot vengono eseguite una dopo l'altra, e un fallimento interrompe la catena. La pulizia parte quindi solo dopo un backup riuscito. Se la destinazione è un filesystem montato, davanti ci vuole una protezione, altrimenti l'esecuzione scrive senza farsi notare dentro il punto di mount vuoto:
ExecStartPre=/usr/bin/mountpoint -q /mnt/backup
Verifica:
systemctl start backup.service
systemctl list-timers backup.timer
journalctl -u backup.service -n 50 --no-pager
systemctl list-timers deve indicare un prossimo orario di avvio. Se lì non compare nulla, il timer non è attivo. Il punto più importante viene alla fine: un'esecuzione che smette in silenzio di partire è il modo normale in cui un backup fallisce. Controlla con systemctl is-failed backup.service, oppure aggiungi come ultima riga ExecStart una chiamata a un servizio di monitoraggio esterno che dia l'allarme quando il segnale di vita quotidiano non arriva.
Mettere alla prova il ripristino
Il test piccolo, ogni mese, cinque minuti
mkdir -p /var/tmp/restore-test
restic restore latest --target /var/tmp/restore-test --include /etc/ssh/sshd_config
diff /etc/ssh/sshd_config /var/tmp/restore-test/etc/ssh/sshd_config && echo "identico"
Con Borg vale lo stesso, tenendo conto che salva i percorsi senza la barra iniziale:
cd /var/tmp/restore-test
borg extract --list ::system-2026-09-03T02:30:00 etc/ssh/sshd_config
Controlla inoltre l'integrità del repository. In entrambi i casi la seconda riga rilegge i dati e ricalcola le somme di controllo, con restic solo su una parte, in modo che l'esecuzione non duri ore:
restic check
restic check --read-data-subset=1/7
borg check
borg check --verify-data
Verifica: restic check termina con no errors were found, borg check senza messaggi di errore. Un repository che viene controllato una sola volta all'anno può essere rimasto danneggiato per undici mesi.
Il test grande, una volta all'anno
Il test piccolo dimostra che i file sono leggibili. Non dimostra che riesci a rimettere in piedi il servizio. Per questo serve il giro completo su un secondo server vuoto: installare il sistema di base, applicare la lista dei pacchetti, collegare il repository, recuperare i dati, importare il dump, avviare i servizi. Prendi il tempo con il cronometro. Quel numero è la tua durata reale di ripristino, e per esperienza è un multiplo di quella stimata.
Annota che cosa è mancato. Sono quasi sempre le stesse cose: un file fuori dai percorsi salvati, un servizio con la configurazione sotto /opt, un certificato senza la chiave dell'account, un database senza utenti e permessi. Quella lista è il vero guadagno del test.
Errori frequenti e soluzioni
Host key verification failed. Il servizio gira come root, e root non ha mai confermato la chiave host della destinazione. Esegui una volta a mano ssh destinazione-backup true oppure ssh-keyscan -H 203.0.113.50 >> /root/.ssh/known_hosts. Da console funziona, nel timer no: quasi sempre è questo l'errore.
Permission denied (publickey). Utente sbagliato, chiave sbagliata oppure permessi sbagliati sulla destinazione: .ssh vuole 700, authorized_keys 600, ed entrambi appartengono all'utente di destinazione.
Is there a repository at the following location? restic non trova nessuna struttura di repository: percorso sbagliato, restic init mai eseguito, oppure destinazione al momento irraggiungibile.
Fatal: wrong password or no key found Il file della password non corrisponde al repository, di solito perché è stato rigenerato in un secondo momento. Controlla con cat -A /etc/restic/repo.pass se ci si è infilato uno spazio di troppo.
repository is already locked exclusively by Un'esecuzione interrotta ha lasciato indietro il suo lock. Verifica prima che non stia più girando nulla, poi restic unlock. Con Borg il messaggio è Failed to create/acquire the lock con l'aggiunta (timeout), e il comando è borg break-lock. Entrambi sono rischiosi finché un'esecuzione è ancora attiva.
Warning: The repository at location ... was previously located at ... L'indirizzo del repository è cambiato e Borg chiede conferma in modo interattivo. Dentro una unit il comando resta così in attesa di una risposta che non arriverà mai. Dopo aver verificato che si tratta dello stesso repository, metti BORG_RELOCATED_REPO_ACCESS_IS_OK=yes nel file di ambiente.
No space left on device sulla destinazione. O la pulizia non parte affatto, oppure gira senza --prune o senza borg compact. Se invece è stato un dump a riempire il filesystem di root, ti aiuta Disco pieno su Linux, come liberare spazio.
L'esecuzione segnala successo ma salva quasi nulla. C'è un'esclusione che taglia troppo, oppure un percorso scritto male. Confronta restic stats latest con il valore del giorno prima. Un backup improvvisamente più piccolo di ordini di grandezza è un allarme, non un successo.
Differenze tra le distribuzioni
- I nomi dei pacchetti sono uguali su tutti e quattro i sistemi:
resticeborgbackup. Le versioni fornite invece no. - Log: Debian 13 e molte installazioni di Debian 12 non portano con sé rsyslog. Lì l'output dell'esecuzione lo trovi soltanto nel journal, quindi con
journalctl -u backup.service. Su Ubuntu 22.04 e 24.04 esistono in più i file sotto/var/log. - Montare gli stati di backup:
restic mounteborg mountrichiedonofuse3. Se il pacchetto manca, il comando si interrompe segnalando l'assenza difusermount3. La strada senza FUSE èrestic restoreoppureborg extract. - Strumento per i database: Debian fornisce soltanto MariaDB, e lì lo strumento si chiama
mariadb-dump, conmysqldumpcome collegamento. Su Ubuntu può girare anche MySQL 8, e lì esiste solomysqldump.
Il controllo finale
La strategia è pronta quando riesci a dimostrare questi sette punti con un comando e non con una supposizione:
restic snapshotsoppureborg listmostra uno stato di questa notte.systemctl list-timers backup.timerindica un prossimo orario di avvio.restic checkoppureborg checknon segnala nessun errore.- Un singolo file è stato ripristinato in questo mese ed è risultato poi identico all'originale.
- Lo scaglionamento corrisponde alla conservazione pianificata e il repository non cresce senza limiti.
- La password è conservata anche in un secondo posto, e da lì l'hai già usata almeno una volta.
- Almeno un supporto accetta i backup senza che il server possa cancellarli.
Se manca il punto quattro, hai una supposizione. Se manca il punto sei, hai spazzatura cifrata. Se manca il punto sette, hai un backup che non sopravvive proprio all'attacco per cui serve più di ogni altra cosa.
Domande frequenti
Che cosa significa la regola 3-2-1 su un singolo server root?
Un RAID o un'immagine del sistema sono già un backup?
restic oppure Borg: quale conviene e quando?
Perché il mio repository non diventa più piccolo anche se cancello gli stati vecchi?
Posso copiare un database in funzione semplicemente come file?
Che cosa succede se perdo la password del repository?
Ogni quanto devo mettere alla prova il ripristino?
Perché il mio backup funziona a mano ma non nel timer systemd?
2026 KernelHost GmbH. Tutti i diritti riservati. Questa guida è protetta dal diritto d'autore. La ripubblicazione su altri siti web, anche parziale o in forma modificata, non è consentita senza il nostro consenso scritto. Le citazioni con indicazione della fonte e un link sono le benvenute.

