- Blade 60.7%
- PHP 38.5%
- JavaScript 0.3%
- CSS 0.3%
- Dockerfile 0.2%
| .agent-notes | ||
| config | ||
| progetti/filament-demo | ||
| .env.example | ||
| .gitignore | ||
| docker-compose.yml | ||
| README.md | ||
| VELOCE.md | ||
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-remotousa host key fisse montate come file:rosu/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
.envcon 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)
.enve chiavi private NON vanno mai versionate (vedi.gitignore)