Backup centralizzati con Backrest/restic su Backblaze + Hetzner
  • Blade 60.7%
  • PHP 38.5%
  • JavaScript 0.3%
  • CSS 0.3%
  • Dockerfile 0.2%
Find a file
2026-09-04 11:51:45 +02:00
.agent-notes Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
config Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
progetti/filament-demo Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
.env.example Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
.gitignore Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
docker-compose.yml Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
README.md Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00
VELOCE.md Infrastruttura backup centralizzati con Backrest e restic 2026-09-04 11:51:45 +02:00

Backup Centralizzati — vps-centrale (Backrest + restic)

Cos'è questo progetto

Infrastruttura Docker per backup centralizzati: un container centrale (vps-centrale) raccoglie i dati di uno o più "clienti" e li salva, cifrati, su due cloud indipendenti: Backblaze B2 e Hetzner Storage Box.

  • Backrest: web UI (porta 9898) per gestire repository, piani e restore
  • restic: il motore di backup (cifratura AES, snapshot incrementali)
  • Perché due cloud: ridondanza — se uno fallisce, i dati sono sull'altro

Architettura

┌────────────────────────────────────────────────────────────┐
│                    vps-centrale (container)                │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ Backrest (UI, porta 9898)                            │  │
│  │ restic (motore backup, cifra con RESTIC_PASSWORD)    │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                            │
│  Volumi montati:                                           │
│  ├── /config          → ./data/backrest-config  (piani/repo)│
│  ├── /root/.cache/restic → ./data/backrest-cache          │
│  ├── /root/.ssh       → ./config/ssh  (chiave Hetzner)     │
│  ├── /data/test       → volume test-data  (:ro)            │
│  ├── /data/cliente    → volume cliente-data (:ro)           │
│  └── /data/staging    → volume staging-data (download SFTP) │
└────────────────────────────────────────────────────────────┘

  Cliente stesso host        Cliente remoto
  ┌──────────────┐           ┌──────────────────────┐
  │ cliente-test │           │ cliente-remoto       │
  │ scrive nel   │           │ (server SFTP, rete   │
  │ volume       │           │  isolata)            │
  │ cliente-data │           │ espone i file via    │
  └──────┬───────┘           │ SFTP (porta 22)      │
         │ volume condiviso  └──────────┬───────────┘
         ▼                             │ pre-hook scp
  vps-centrale legge :ro               ▼
         │                    /data/staging (download)
         ▼                             │
  ┌─────────────────────────────────────┘
  ▼
  restic backup → cifra → Backblaze B2  (HTTPS)
  restic backup → cifra → Hetzner       (SFTP, chiave SSH)

I tre scenari di "cliente"

Scenario Meccanismo Come funziona
Dati locali Volume Docker condiviso Il cliente scrive in un volume montato :ro anche su vps-centrale
Cliente remoto SFTP → staging vps-centrale scarica i file via scp in /data/staging (pre-hook) poi backuppa
Server separato come "cliente remoto" Il cliente espone una cartella SFTP; il backup è sempre un pull da vps-centrale

Principio: è sempre vps-centrale che prende i dati (pull). Il cliente è passivo: non ha restic, non ha credenziali cloud, non sa di essere backuppato. Tutte le credenziali stanno solo su vps-centrale.

Composizione del progetto

backup_centralizzati_2/
├── docker-compose.yml          ← definizione dei servizi
├── .env                        ← credenziali (MAI versionare)
├── config/
│   ├── ssh/                    ← chiave privata Hetzner + known_hosts
│   └── ssh-cliente/            ← authorized_keys del cliente remoto
│       └── hostkeys/           ← host key FISSE del server SFTP di test
├── data/
│   ├── backrest-config/        ← config Backrest (piani, repo) — persistente
│   └── backrest-cache/         ← cache restic (solo velocità)
├── .agent-notes/               ← appunti di sviluppo (questo progetto)
└── README.md

Servizi (docker-compose.yml)

Servizio Container Immagine Ruolo
backup-centrale vps-centrale garethgeorge/backrest Backup centrale (Backrest + restic)
cliente-test cliente-test alpine Simula cliente locale (volume condiviso)
cliente-remoto cliente-remoto atmoz/sftp Simula cliente remoto (server SFTP)

Tutti con restart: unless-stopped (ripartono dopo blackout/reboot).

Note sui volumi

  • /config è il path reale dove Backrest salva la config (non /root/.config/backrest!) — scoperto dopo aver perso i piani una volta.
  • Il volume cliente-data è montato :ro (read-only) su vps-centrale: il backup può leggere, mai modificare i dati originali.
  • cliente-remoto usa host key fisse montate come file :ro su /etc/ssh/ssh_host_*_key → l'impronta non cambia a ogni ricreazione → la verifica host key può restare ATTIVA.

Prerequisiti

  • Docker + Docker Compose
  • Account Backblaze B2 con bucket (es. backup-cpwb)
  • Hetzner Storage Box (SFTP su porta 23)
  • File .env con le credenziali (vedi sotto)

Configurazione iniziale

1. Creare il file .env

cp .env.example .env   # poi riempirlo (vedi sotto)
B2_ACCOUNT_ID=il_tuo_keyID
B2_ACCOUNT_KEY=la_tua_applicationKey
RESTIC_PASSWORD=password_forte_di_cifratura

RESTIC_PASSWORD è la password con cui restic cifra i repository. Se la perdi, i backup sono irrecuperabili. Salvarla in un password manager.

2. Chiavi SSH per Hetzner (SFTP)

ssh-keygen -t ed25519 -f config/ssh/id_ed25519 -N ""

Caricare la chiave pubblica sul pannello Hetzner Storage Box: ssh-copy-id -p 23 -s u396408-sub2@u396408.your-storagebox.de

3. Avviare

docker compose up -d

Backrest è su http://localhost:9898 (creare utente al primo accesso).

4. Configurare i repository nella UI Backrest

Campo Backblaze Hetzner
URI b2:nome-bucket:/backup sftp:utente@host:23/backup
Password RESTIC_PASSWORD RESTIC_PASSWORD
Env vars B2_ACCOUNT_ID, B2_ACCOUNT_KEY (vuoto)

5. Configurare i piani

Ogni piano = path + repository + schedule (+ eventuali hook). Per la ridondanza serve un piano per cloud (Backrest non permette due repository per piano).

Backup e restore — comandi utili

# Backup manuale su Backblaze
docker compose exec backup-centrale restic -r b2:backup-cpwb:/backup backup /data/test

# Backup manuale su Hetzner
docker compose exec backup-centrale restic -r sftp:u396408-sub2@u396408.your-storagebox.de:23/backup backup /data/test

# Lista snapshot
docker compose exec backup-centrale restic -r b2:backup-cpwb:/backup snapshots

# Contenuto di uno snapshot
docker compose exec backup-centrale restic -r b2:backup-cpwb:/backup ls <ID>

# Restore di un file da uno snapshot
docker compose exec backup-centrale restic -r b2:backup-cpwb:/backup restore <ID> \
  --include /data/test/percorso/file.txt --target /tmp/restore-test

# Sbloccare lock stantii (dopo crash/blackout)
docker compose exec backup-centrale restic -r b2:backup-cpwb:/backup unlock

Flusso cliente remoto (SFTP → staging → backup)

Il piano ha un pre-hook che scarica i file dal cliente prima del backup:

sh -c "mkdir -p /data/staging && scp -i /root/.ssh/cliente_key -P 22 -r cliente@cliente-remoto:/data/ /data/staging/"

Comportamento in caso di errore del hook: cancel (se il download fallisce, il backup non parte — mai backuppare dati vecchi).

Chiave SSH del cliente remoto

ssh-keygen -t ed25519 -f config/ssh/cliente_key -N ""
cp config/ssh/cliente_key.pub config/ssh-cliente/authorized_keys

L'utente SFTP è cliente con uid 1000 (deve combaciare con l'owner dei file montati, altrimenti sshd rifiuta la chiave per StrictModes).

Problemi noti e soluzioni

Problema Soluzione
Piano fallisce "repository is already locked" restic unlock sul repo
Container non vede file modificati nelle cartelle montate docker compose up -d --force-recreate <servizio> (bind mount "congelato" su Docker Desktop/WSL)
Piani spariscono dopo docker compose down Verificare che /config sia montato su ./data/backrest-config
Dopo un blackout i container non ripartono Devono avere restart: unless-stopped nel compose

Sicurezza

  • I dati viaggiano cifrati due volte: canale SSH/HTTPS + cifratura restic
  • Le credenziali cloud stanno SOLO in vps-centrale (mai sui clienti)
  • La verifica host key è ATTIVA (known_hosts + host key fisse)
  • .env e chiavi private NON vanno mai versionate (vedi .gitignore)