Aller au contenu

Backups

Architecture

graph LR
    subgraph cluster["Proxmox cluster"]
        galahad[galahad
LXC 100 dns-failover
LXC 102 vault] lancelot[lancelot
LXC 101 logs
LXC 103 pbs] end subgraph penny["penny (RPi 4)"] volumes[Volumes Docker
staging → /mnt/ssd/.restic-staging] configs[Configs bind-mount
/mnt/ssd/config/*] nfs[NFS server
/mnt/ssd/pbs-datastore] end galahad -->|PBS API| PBS[PBS LXC 103
192.168.1.33] lancelot -->|PBS API| PBS PBS -->|NFS mount| nfs volumes --> restic configs --> restic restic[restic backup 3h
chiffre AES-256] --> B2[Backblaze B2
gabin-homelab-backups/restic] vault102[LXC 102 vault] -->|restic-direct 2h| B2vault[Backblaze B2
restic-vault] Git[Configs + Scripts] -->|git push| GitHub[GitHub
homelab-config prive]

Chiffrement : AES-256 cote client (restic pour penny + Vaultwarden). PBS chiffre au niveau datastore (AES-256-GCM).

Regle 3-2-1 :

  • 3 copies : live (SSD/eMMC) + PBS local (penny SSD via NFS) + Backblaze B2 (restic chiffre)
  • 2 supports : SSD/eMMC + cloud
  • 1 copie hors-site : Backblaze B2

Proxmox Backup Server (PBS)

Infrastructure

Element Detail
LXC 103 "pbs" sur lancelot, unprivileged, Debian 13, IP 192.168.1.33
Datastore "main" /mnt/datastore (bind-mount depuis lancelot /mnt/pbs-nfs)
Stockage reel NFS sur penny, export /mnt/ssd/pbs-datastore (65536 chunk dirs)
NFS export all_squash anonuid=100034 (UID mappe du LXC unprivileged)
UI backup.home.gabin-simond.fr via Traefik → 192.168.1.33:8007
Auth Authelia OIDC realm "authelia" + comptes locaux break-glass

Comptes PBS

Voir comptes.md pour la convention complete.

Compte Role Usage
root@pam Superuser Break-glass uniquement
gabins@authelia Admin sur / Login quotidien UI via OIDC 2FA
gabins@pbs Admin sur / Break-glass si Authelia down
svc-pve-backup@pbs!pve DatastorePowerUser sur /datastore/main Jobs backup PVE Datacenter

Backup des LXC via PBS

Les deux nodes PVE (galahad + lancelot) envoient leurs LXC directement au PBS via l'API native. Plus besoin de vzdump-daily.sh + rsync + pull vers penny.

LXC Contenu Node PVE Criticite
100 (dns-failover) AdGuard secondaire galahad Moyenne
101 (logs) Loki + Grafana lancelot Faible
102 (vault) Vaultwarden galahad Critique
103 (pbs) PBS lui-meme lancelot Moyenne (reconstructible)

vzdump hook temporaire

Les LXC sont backupes en mode stop (pas snapshot) car les rootfs sont sur stockage local (dir, pas ZFS). Le hook /usr/local/bin/vzdump-permfix-hook.sh corrige un bug de permissions sur pct.conf pour les LXC unprivileged. A supprimer quand les rootfs seront migres sur ZFS (mode snapshot natif).

vzdump-permfix-hook.sh

Hook vzdump enregistre dans /etc/vzdump.conf sur galahad et lancelot :

# /etc/vzdump.conf
tmpdir: /tmp
script: /usr/local/bin/vzdump-permfix-hook.sh

Le hook lance un watcher en arriere-plan a backup-start qui surveille l'apparition de pct.conf dans le tmpdir et corrige ses permissions (chmod a+rX dirs, chmod a+r fichiers) pour que lxc-usernsexec (UID 100000) puisse les lire.


Vault — restic-direct vers B2

Vaultwarden (LXC 102 sur galahad) dispose d'un backup restic independant, direct vers B2. Ce backup est complementaire de PBS et garantit une copie hors-site meme si PBS ou le NFS sont en panne.

Element Detail
Script /usr/local/bin/vault-backup.sh dans LXC 102
Cron Quotidien 02h00
Repo b2:gabin-homelab-backups:restic-vault
Retention 7 daily / 4 weekly / 6 monthly
Methode SQLite atomic snapshot (.backup API) + /opt/vaultwarden/ complet
Notification ntfy (low OK, high FAIL)

penny — restic vers B2

Ce qui est sauvegarde

Volumes Docker (stages puis backup) :

Donnee Volume Criticite
Beszel (historique monitoring) config_beszel-data Faible
Portainer (config Docker) config_portainer-data Moyenne

Configs avec secrets :

Donnee Chemin Criticite
Authelia (DB SQLite + cle OIDC + config + secrets) /mnt/ssd/config/authelia/ Critique
AdGuard (config avec rewrites) /mnt/ssd/config/adguard/ Haute
Traefik (config + dynamic routes) /mnt/ssd/config/traefik/ Haute
Homepage (dashboard config) /mnt/ssd/config/homepage/ Faible
Scripts systeme /mnt/ssd/config/scripts/ Moyenne
Boot config (cmdline, config.txt) /mnt/ssd/config/boot/ Haute
System config (fstab, sysctl) /mnt/ssd/config/system/ Haute

Via Git (a chaque modification)

Donnee Repo Visibilite
Configs applicatives (Traefik, AdGuard, Homepage, etc.) homelab-config Prive
Config systeme (boot, fstab, udev, sysctl, crontab) homelab-config Prive
Scripts (monitor, backup, vzdump, proxmox) homelab-config Prive
Templates Authelia (.example, sans secrets) homelab-config Prive
Documentation homelab-doc Public

Script homelab_backup.sh

Execution : cron quotidien a 3h (0 3 * * *)

Fonctionnement :

  1. Verification preflight (.restic-env present, restic installe)
  2. Stage chaque volume Docker vers /mnt/ssd/.restic-staging/<label>/
  3. restic backup : staging + configs → B2 (chiffre AES-256)
  4. Nettoyage du staging
  5. restic forget : retention 7 daily / 4 weekly / 6 monthly + prune
  6. Notification ntfy (succes ou echec avec duree)

Verification d'integrite : restic-check-monthly.sh (1er du mois, 4h)

  • Verification structure (indexes, packs)
  • Verification 10% donnees aleatoires (detection bit rot)
  • Alerte ntfy en cas d'echec

Destinations

Destination Chemin Retention Chiffrement Cout
Backblaze B2 (restic penny) gabin-homelab-backups/restic 7d / 4w / 6m AES-256 client-side Gratuit (<10 Go)
Backblaze B2 (restic vault) gabin-homelab-backups/restic-vault 7d / 4w / 6m AES-256 client-side Gratuit
PBS datastore "main" (NFS penny) /mnt/ssd/pbs-datastore Configuree dans PBS AES-256-GCM Gratuit

Ce qui n'est PAS sauvegarde (reconstructible)

Donnee Raison
Images Docker docker compose pull
Cache Docker (overlay2) Reconstruit automatiquement
Certificats TLS (Traefik) Regeneres par Let's Encrypt
Logs Ephemeres, pas critiques
Tailscale state Re-auth suffit (tailscale up)
Proxmox config Reinstallation via scripts (proxmox-post-install.sh)
PBS LXC 103 Reconstructible (config + datastore sur NFS penny)

Restauration

Restaurer un LXC depuis PBS

# Via l'UI PBS (backup.home.gabin-simond.fr) :
# 1. Selectionner le snapshot dans le datastore "main"
# 2. Bouton "Restore" → choisir le node PVE cible
#
# Via CLI PVE :
pvesh create /nodes/<node>/lxc -archive <PBS-backup-ID> -storage local

Restaurer Vaultwarden depuis restic B2

# Depuis LXC 102 (ou un nouveau LXC)
source /root/.restic-env && export RESTIC_PASSWORD RESTIC_REPOSITORY B2_ACCOUNT_ID B2_ACCOUNT_KEY
restic restore latest --target /tmp/restore --tag vault
cp -a /tmp/restore/opt/vaultwarden/. /opt/vaultwarden/
# Restaurer le snapshot SQLite propre
cp /tmp/restore/var/backups/vault/db.sqlite3 /opt/vaultwarden/data/db.sqlite3
rm -rf /tmp/restore
systemctl restart vaultwarden

Restaurer un volume Docker (penny)

source /root/.restic-env && export RESTIC_PASSWORD RESTIC_REPOSITORY B2_ACCOUNT_ID B2_ACCOUNT_KEY
restic restore latest --target /tmp/restore --include "/mnt/ssd/.restic-staging/beszel"

docker compose stop beszel
docker run --rm \
    -v config_beszel-data:/data \
    -v /tmp/restore/mnt/ssd/.restic-staging/beszel:/source:ro \
    alpine sh -c "rm -rf /data/* && cp -a /source/. /data/"
docker compose up -d beszel
rm -rf /tmp/restore

Restaurer une config (penny)

source /root/.restic-env && export RESTIC_PASSWORD RESTIC_REPOSITORY B2_ACCOUNT_ID B2_ACCOUNT_KEY
restic restore latest --target /tmp/restore --include "/mnt/ssd/config/authelia"

docker compose stop authelia
cp -a /tmp/restore/mnt/ssd/config/authelia/. /mnt/ssd/config/authelia/
docker compose up -d authelia
rm -rf /tmp/restore

Restauration complete (nouveau RPi)

Voir break-glass.md pour la procedure pas-a-pas.

  1. Installer DietPi
  2. Cloner homelab-config depuis GitHub
  3. Suivre le README (copier boot, udev, fstab, network, docker)
  4. Restaurer .restic-env depuis la cle USB chiffree
  5. restic restore latest depuis B2
  6. Restaurer les volumes et configs
  7. Regenerer les secrets Authelia si necessaire (voir README)
  8. docker compose up -d

Credentials restic

# /root/.restic-env (chmod 600, gitignored)
RESTIC_PASSWORD=<mot-de-passe-chiffrement>
RESTIC_REPOSITORY=b2:gabin-homelab-backups:restic
B2_ACCOUNT_ID=<keyID>
B2_ACCOUNT_KEY=<applicationKey>

Ce fichier doit etre sur la cle USB chiffree

Sans .restic-env, les backups B2 sont illisibles. Perte de ce fichier = perte des backups.

Bucket gabin-homelab-backups sur Backblaze B2, region US West. Application key limitee a ce bucket uniquement (read + write).


Voir aussi