Vai al contenuto

Backup B2 da US a EU: GDPR, Hetzner, restic e il mio podio dei rimpianti

Backup B2 da US a EU: GDPR, Hetzner, restic e il mio podio dei rimpianti

Backup B2 da US a EU: GDPR, Hetzner, <a href=restic e il mio podio dei rimpianti” title=”Backup B2 da US a EU: GDPR, Hetzner, restic e il mio podio dei rimpianti” loading=”eager” decoding=”async” />

Aprile 2026, finestra di manutenzione concordata con i clienti editoriali, finestra di pazienza concordata con me stesso. Ho consolidato la strategia di data residency portando i repository backup b2 us eu gdpr in zona EU-Central sull’infrastruttura di Romiltec e dei tenant gestiti su AI Multisite. La scelta è di governance: allineare i repository ai requisiti dei clienti italiani e semplificare l’audit cliente sul perimetro di sovranità del dato. Tre TB cumulati di dataset compressi e cifrati, spostati con restic su tre cluster di tenant in produzione, con un calcolo di egress che mi ha tolto qualche giorno di sonno. Negli altri post di Production ho raccontato decisioni di stack di AI Multisite: questa è laterale ma critica, perché il backup è uno di quei lavori in cui funziona significa molto poco rispetto a funziona, è ripristinabile, è governato.

Il punto di partenza: backup B2 region US-West

Quando ho avviato Romiltec nel 2023, la scelta iniziale di provider per il backup off-site era stata Backblaze B2, region default us-west-002. Tre motivi banali e onesti, in quell’ordine: pricing aggressivo (a quei volumi, B2 costava un terzo di S3 standard), API S3-compatible (mc, restic, rclone funzionavano out-of-the-box), affidabilità storica (B2 girava da anni, nessun fallimento sistemico documentato). La region US era stata scelta inizialmente per disponibilità immediata e per il pricing del piano di partenza; oggi, con il perimetro di clienti italiani che gestisco, la scelta naturale di governance è diversa.

Stack di backup, in versione 2024-2025:

  • Source: VM Debian Proxmox con dataset ZFS dedicati per ogni tenant, snapshot orarie locali con retention 24h
  • Tool di backup: restic, repository per tenant, encryption AES-256 con passphrase gestita via Vault
  • Target: B2 region us-west-002, bucket per cluster, lifecycle rules per retention
  • Retention policy: daily 30, weekly 12, monthly 12 (gestita da restic forget --prune)
  • Schedulazione: cron settimanale con orchestrator interno che parallelizza fino a 4 tenant per finestra
  • Verifica: restic check mensile, restore di sample mensile su VM di staging

Il setup, sulla carta, era pulito. Il problema iniziato a maturare a metà 2025 era altrove.

Perché ho deciso di migrare

Tre vincoli convergenti, in ordine di gravità.

Primo: data residency e governance dei dataset editoriali italiani. I dataset più rilevanti che gestisco sono i database delle redazioni dei tenant editoriali. Articoli, anagrafiche autori, dati di traffico aggregati. Romiltec opera come responsabile del trattamento ex art. 28 del Regolamento UE 2016/679 per conto dei tenant clienti, che restano titolari. Quando un cliente fa un audit interno o di un suo partner commerciale, una delle prime domande è dove sono fisicamente i miei backup?. Volevo che la risposta fosse banale: in un datacenter europeo, sotto contratto EU. La direzione naturale per semplificare audit cliente e perimetro di data residency è tenere i backup in zona EU. Punto.

Secondo: latenza di restore. Il restore da region US a un nodo Hetzner Falkenstein o a un nodo italiano richiede di pullare TB attraverso l’Atlantico. La banda dei nostri server non è il collo di bottiglia (10 Gbps simmetrici disponibili sui nodi di backup), ma il throughput end-to-end è limitato dai peering transcontinentali di Backblaze. Su un test di restore reale di un dataset da 80 GB, il tempo wall-clock da us-west-002 era di circa 2h40, da EU sarebbe stato in zona 35-45 minuti stimati. Su un disaster recovery serio, quei due ore di delta sono il tempo in cui un caporedattore cambia provider.

Terzo: economics dell’egress in fase di restore. Backblaze offre egress gratuito verso Cloudflare. La nostra infra non gira su Cloudflare per tutto: gli origin Hetzner pullano direttamente da B2. L’egress B2 (out) verso un IP non-Cloudflare è $0.01 per GB. Su un disaster recovery completo di un cluster da 1.5 TB, sono $15 di egress. Niente di drammatico, ma su sei mesi di sviluppi e restore di staging, il conto cumula. Backup in EU sullo stesso provider, con un disegno di rete in cui Hetzner Falkenstein parla con B2 EU-Central tramite peering europei, abbatte il costo di pull e migliora il tempo.

La pianificazione tecnica

La regola che ho seguito da subito: la migrazione non è un cp -r. È un’operazione che produce un nuovo repository in EU, valida la consistenza del nuovo, e solo dopo dismette il vecchio. Niente big bang, niente fingers crossed.

Lo scheletro della pianificazione, in ordine cronologico.

Fase 1: provisioning del bucket EU. Bucket B2 EU-Central creato con lifecycle rules identiche al bucket US, encryption-at-rest abilitato, application key con permessi minimi (writeFiles, listAllBucketNames, readFiles). Validazione che le SCC e il DPA di Backblaze coprano la nuova region (sì, copertura standard).

Fase 2: re-init del repository restic in EU. Su un nodo di staging Hetzner ho fatto restic init su un nuovo repository EU-Central per ciascun tenant, con la stessa passphrase del repository US (non la stessa chiave master di restic, attenzione: restic genera una nuova chiave master, ma la passphrase di unlock è la stessa per coerenza operativa).

Fase 3: backup parallelo per due settimane. Per due settimane il cron di backup ha pushato sia su US (vecchio repo) sia su EU (nuovo repo) per ogni tenant. Costo doppio, ma con la garanzia che durante la fase di switch nessuna finestra di backup è scoperta. È la tipica strategia blue/green applicata al backup.

Fase 4: backfill storico. Qui c’era una scelta. Opzione A: copiare i blob B2 US verso B2 EU con b2 sync o rclone sync (sì, B2 supporta inter-region copy, ma a costo di egress US-out). Opzione B: ripartire la retention da zero in EU, dismettere la region US a valle del cutover. Ho scelto B, per due motivi: il restore di backup vecchi più di 30 giorni è raro (quasi nulla a quel ramo della retention finisce davvero in un restore reale), e il costo di una sync transcontinentale di 3 TB era nell’ordine del centinaio di euro. Lascio che la nuova retention si autocompleti su EU. La region US la dismetto a cutover completato, senza overlap di failover storico: tenere ulteriormente dataset EU in zona US sarebbe in contraddizione con la motivazione di governance della migrazione.

Fase 5: integrity check completo sul repository EU. restic check --read-data su ciascun repository EU dopo il primo round di backup completo. Pesante (è un download di tutti i pack file e verifica MAC su ciascuno), ma è l’unico modo per essere sicuri che i dati siano integri end-to-end, non solo che siano arrivati. Il check non è un’opzione, è il momento in cui un backup smette di essere promesso e diventa verificato.

Fase 6: restore reale in staging. Per ciascun tenant ho fatto un restore reale di uno snapshot recente su una VM di staging, con restic restore latest --target /mnt/staging, e ho rimontato l’applicazione (database, file media WordPress, asset) per verificare che il restore non solo arrivasse, ma servisse. Senza questo passo, il backup è teoria.

Fase 7: cutover. Solo dopo le fasi 5 e 6 ho switchato il bucket primario nel cron e disabilitato il push su US. A cutover validato (ultima settimana con doppia scrittura più check su EU verde), ho dismesso la region US senza tenere overlap.

Hetzner come compute, B2 EU come storage

Una nota architetturale. La mia infrastruttura compute principale è su Hetzner (Falkenstein e Helsinki, con qualche nodo italiano per latency-sensitive). Hetzner offre egress generoso (20 TB inclusi al mese su buona parte dei piani), e i suoi peering europei con Backblaze B2 EU sono ottimi: throughput sostenuto tra Falkenstein e B2 Amsterdam supera comodamente i 600 Mbps su connessione singola.

Questa combinazione è uno dei motivi tecnici della migrazione. Hetzner + B2 EU è una pipeline di backup all-EU, con costi e latenze prevedibili e con un audit di data residency che si scrive in mezza pagina invece che in un trattato di SCC. È esattamente la semplificazione che cercavo.

Per chi parte da zero, il pattern che consiglierei è questo:

  1. Compute su Hetzner (o equivalente provider EU)
  2. Source dataset su ZFS, snapshot locale ogni ora con retention breve
  3. Backup off-site con restic (o borgbackup, equivalente in tante feature) verso B2 EU-Central
  4. Encryption-at-rest gestita lato restic (la repository encryption è già nativa)
  5. Retention multistadio: locale 24h, off-site daily 30 / weekly 12 / monthly 12
  6. restic check --read-data mensile, restore reale a campione mensile
  7. Audit log delle operazioni di backup separato dai log applicativi

Niente di esotico. La differenza la fa il fare ciascuno di questi punti seriamente, senza saltarne uno.

Tre lezioni operative dalla migrazione

Nella migrazione tre cose mi hanno insegnato qualcosa che voglio mettere a verbale. Le elenco in ordine di importanza, non di drammaticità.

Una: la data residency è una decisione di governance, non un dettaglio infra. Va presa con anticipo, definita nel contratto col cliente, riflessa nella scelta di region fin dal disegno iniziale. Quando si presenta come scelta di governance positiva è semplice da raccontare in audit; quando si presenta come reazione a una richiesta esterna costa attenzione, doppia scrittura, calcoli di egress che potevi non fare. Il take-home: la region di backup è una decisione architetturale, va trattata come tale.

Due: non aver chiesto a Backblaze una staged migration assistita. Backblaze ha programmi di migrazione assistita per clienti business con dataset oltre il TB. In versione semplificata: ti aiutano a fare la sync inter-region a costo agevolato (a volte zero, a seconda del piano e del volume). Non l’ho chiesto. Mi sono affidato alla mia pianificazione interna e ho assorbito il costo della doppia scrittura per due settimane. Non è stato un errore catastrofico (il calcolo che ho fatto regge), ma una conversazione di trenta minuti con il loro account technical manager mi avrebbe fatto risparmiare egress e tempo. Non l’ho cercata perché posso fare da solo è una tentazione del founder tecnico. Posso non significa devo.

Tre: il primo restic check post-migrazione l’ho schedulato come step opzionale, non come parte del flow. Dopo il primo round di backup completo su EU ho fatto il restic check --read-data in un secondo momento, nel pomeriggio del giorno successivo, invece che immediatamente come blocco di gate del cutover. Il check non ha trovato problemi e tutto è passato. Ma è stato fortunato: il backup esiste e il backup è leggibile end-to-end sono due cose diverse, e nelle ore in cui il check non era ancora passato avevo, di fatto, una promessa non verificata. La regola operativa che ho aggiornato è: il check di integrità è step di gate del cutover, non opzionale, schedulato nello stesso runbook della migrazione e con un esito che blocca il cutover se non passa.

Cosa mi sono portato a casa da questa migrazione

Tre cose, in ordine di importanza operativa.

Una. Il backup è incompleto finché non hai testato il restore. Sembra una banalità da blog di sysadmin, ed è banale solo per chi non ha mai aperto un disaster recovery con il cliente al telefono e ha scoperto, lì in tempo reale, che lo snapshot più recente non era ripristinabile per un bug nella catena di compressione. Il restore reale a campione mensile non è una pratica di igiene, è una pratica di sopravvivenza.

Due. Compliance non è un layer successivo, è una constraint di disegno. Migrare un backup da una region US a una region EU dopo due anni di operatività mi è costato attenzione, doppia scrittura, calcoli di egress. Avrei evitato tutto questo se avessi disegnato il backup in EU dal giorno zero, sapendo che gestivo dataset editoriali italiani. La compliance va incorporata come vincolo iniziale, non aggiustata dopo.

Tre. Gli step di verifica vanno schedulati come parte del flow di migrazione, non come step opzionali a valle. Il restic check --read-data è la differenza fra backup arrivato e backup ripristinabile. Nel 2026 di Romiltec, ogni runbook di migrazione che tocca repository di backup ha il check di integrità come step bloccante, con un esito che fa fail del cutover se non è verde. Accetterò di aspettare due ore invece di trenta minuti per un cutover, in cambio di una garanzia che non posso scambiare.

Il backup che voglio per Romiltec a 18 mesi da qui

Tre note per il futuro, da rileggere fra un anno e mezzo.

Vorrei muovere la encryption key custody su un sistema HSM-backed (probabilmente HashiCorp Vault con auto-unseal su KMS Hetzner se sarà disponibile, oppure HSM fisico in colocation se Vault non basterà). Le passphrase manuali sono un trade-off ragionevole oggi, ma a un certo numero di tenant diventano un single point of failure umano.

Sto valutando, in roadmap interna, di rinforzare la regola classica dei backup 3-2-1 (3 copie, 2 supporti, 1 off-site) verso una postura 3-2-1-1 con un secondo target su un provider EU indipendente. È un ragionamento di resilienza, non urgenza, e va dimensionato con calma sui carichi reali. Il principio è semplice: a fronte di un disaster recovery in cui anche un provider primario venisse meno, avere un secondo target non in dipendenza è la differenza fra brutto trimestre e cliente che perde dieci anni di archivio.

Vorrei pubblicare al cliente una dashboard di compliance dei backup in cui vede, in tempo reale, lo stato degli ultimi snapshot per i suoi dataset, l’esito dell’ultimo restic check, l’esito dell’ultimo restore reale di staging, e la region fisica dove i suoi backup vivono. È una rifinitura di posizionamento commerciale, e una rifinitura di ownership condivisa: il cliente che vede lo stato dei suoi backup è un cliente che capisce, non solo che paga e si fida.

Stavo per chiudere questa migrazione con un commit di celebration sul changelog interno e una pacca sulla spalla. La cosa più utile è scriverla come un report onesto, con tre lezioni operative invece che con tre vittorie. È più utile così, anche per chi mi legge: il backup che funziona è quello che hai testato, è quello in cui la data residency è una decisione di governance esplicita, ed è quello che hai reso ripristinabile da qualcuno diverso da te il giorno in cui non saresti operativo.