diff --git a/infra/backup-strategy-2026-04-18.md b/infra/backup-strategy-2026-04-18.md new file mode 100644 index 0000000..9ba2b79 --- /dev/null +++ b/infra/backup-strategy-2026-04-18.md @@ -0,0 +1,336 @@ +--- +title: Stratégie de backup DAEMON +type: infra +created: 2026-04-18 +updated: 2026-04-18 +owner: jerem +status: draft-en-cours-de-déploiement +tags: + - infra + - backup + - kopia + - security +related: + - "[[infra/vps-config-2026-04-17]]" + - "[[_adn/soul]]" +--- + +# Stratégie de backup DAEMON — 2026-04-18 + +> **État** : plan validé, déploiement en cours. NAS en attente de validation par Fab. + +--- + +## 🎯 Objectif + +Protéger les données critiques de l'écosystème DAEMON (vault Obsidian, data Notion, configs infrastructure) contre : +- Panne matérielle VPS +- Corruption / suppression accidentelle +- Compromission sécurité (ransomware, intrusion) +- Perte compte iCloud / Google +- Faillite / coupure d'un fournisseur + +Règle appliquée : **3-2-1** (3 copies, 2 médias différents, 1 offsite minimum). En réalité on vise **3-3-2** : 3 destinations de backup, 3 médias distincts, 2 offsites. + +--- + +## 📊 Ce qui est backupé (par criticité) + +### Tier 1 — catastrophique si perdu (backup quotidien) + +| Source | Contenu | Pourquoi critique | +|---|---|---| +| `/home/jerem/vault/` | Vault Obsidian (cerveau DAEMON) | Contient toute la mémoire, les règles, l'historique | +| `/home/jerem/notion-backup/` | Export Notion quotidien en Markdown | Clients, projets, habitudes, journaling | + +### Tier 2 — reinstallable mais douloureux (backup hebdomadaire le dimanche) + +| Source | Contenu | +|---|---| +| `/home/jerem/.openclaw/` | Config OpenClaw, credentials Google/Gmail | +| `/home/jerem/daemon-infra/` | Scripts, systemd units, config nginx/wireguard | +| `/etc/systemd/system/` | Services systemd | +| `/etc/nginx/` | Config reverse proxy | +| `/etc/wireguard/` | Tunnel VPN | + +### Tier 3 — pas backupé + +- Logs OpenClaw +- Caches, sessions +- Dossiers `/tmp/`, `/var/cache/` +- Anything ephemeral + +### Non backupé volontairement + +- **Doppler** : MFA activé, régénération possible en 4h. Risque accepté. +- **Bot tokens Slack/WhatsApp** : stockés dans Doppler, idem ci-dessus. + +--- + +## 🗺️ Topologie + +``` + /home/jerem/vault (live VPS) + │ + ┌──────────────────────┼──────────────────────┐ + │ │ │ + ▼ ▼ ▼ + Kopia local Kopia NAS ami (WebDAV) Kopia Google Drive + /var/backups/ nasprodfab.duckdns gdrive jerem + 7 jours rétention 5 ans rétention 5 ans rétention + │ │ │ + └── restore rapide └── offsite physique └── offsite cloud +``` + +**Pas d'offsite** : Kopia local (même machine que la source). +**Offsite physique** : NAS Ugreen de Fab. +**Offsite cloud** : Google Drive (compte jerem, 5TB). + +--- + +## 🔒 Sécurité + +### Chiffrement + +- **Côté client, avant transit** : Kopia AES-256-GCM +- Le NAS de Fab voit uniquement des blobs chiffrés illisibles +- Google Drive idem + +### Gestion de la passphrase Kopia + +La passphrase de chiffrement est stockée à **3 endroits** : + +1. **VPS** : `/root/.kopia-password` (mode `600`, root-only) +2. **Bitwarden** : entrée "Kopia DAEMON backup passphrase" +3. **Papier** : dans le coffre physique de Jerem + +**Si VPS détruit + Bitwarden perdu → backups restaurables via la copie papier.** +**Si tous les 3 sont perdus → backups illisibles. Risque accepté : probabilité extrêmement faible.** + +### Secrets NAS (WebDAV) + +Stockés dans **Doppler** `daemon-infra/prd` : + +- `NAS_WEBDAV_URL` +- `NAS_WEBDAV_USER` +- `NAS_WEBDAV_PASS` + +Injectés dans l'environnement Kopia au moment du backup par le script de démarrage, jamais écrits en clair sur disque. + +### Secrets Google Drive + +Utilise l'OAuth Google déjà configuré pour Calendar/Gmail. Refresh token dans Doppler : `GOOGLE_REFRESH_TOKEN`. + +--- + +## ⏰ Planning + +| Quand | Quoi | Où | +|---|---|---| +| Chaque nuit à **3h00 Paris** (heure VPS fixe, ne change jamais en voyage) | Snapshot Kopia Tier 1 + 2 | Local VPS + NAS + gdrive | +| Chaque dimanche **3h30** | Snapshot Tier 2 seul si rien de Tier 1 n'a tourné | Idem | +| Chaque lundi **4h00** | **Test de restore automatique** (extraction d'un snapshot random vers `/tmp`, comparaison hash) | Local | + +**Pourquoi 3h Paris fixe** : le backup tourne sur le VPS (pas sur le Mac), donc l'heure physique de Jerem importe peu. 3h Paris = toujours pendant une période de faible activité chez lui, peu importe le fuseau. + +--- + +## 📦 Rétention GFS (Grandfather-Father-Son) + +Kopia applique automatiquement : + +| Horizon | Snapshots gardés | +|---|---| +| 7 derniers jours | Tous (1 par jour) | +| 4 dernières semaines | 1 par semaine | +| 12 derniers mois | 1 par mois | +| 5 dernières années | 1 par an | + +**Total théorique** : ~28 snapshots actifs à n'importe quel instant. +**Taille réelle** : grâce à la déduplication Kopia (chunks unique stockés une seule fois), ~150-300 MB pour le repo complet, pas 28× la taille du vault. + +--- + +## 🔄 Pipeline de backup (nightly 3h) + +``` +┌──────────────────────────────────────────────────────────────┐ +│ 0. Pull secrets Doppler (NAS_*, GOOGLE_*) │ +│ │ +│ 1. Notion export │ +│ ├─ notion-export → /home/jerem/notion-backup/*.md │ +│ ├─ git commit + push (repo Gitea dédié) │ +│ ├─ SI ÉCHEC : alerte Slack + continue (export J-1 dispo) │ +│ └─ ping Kuma push monitor "notion-export-ok" │ +│ │ +│ 2. Kopia snapshot local │ +│ └─ sources : vault, notion-backup, daemon-infra, │ +│ .openclaw, /etc/* (hebdo seulement) │ +│ │ +│ 3. Kopia sync vers NAS ami (WebDAV) │ +│ └─ SI ÉCHEC (NAS offline) : alerte + continue │ +│ │ +│ 4. Kopia sync vers Google Drive │ +│ └─ SI ÉCHEC : alerte + continue │ +│ │ +│ 5. Kopia maintenance (GFS prune, compaction) │ +│ │ +│ 6. Ping Kuma "daemon-backup-ok" │ +└──────────────────────────────────────────────────────────────┘ +``` + +**Philosophie** : jamais d'arrêt brutal. Une étape qui rate alerte et laisse les autres continuer. + +--- + +## 🚨 Monitoring et alertes + +### Uptime Kuma Push Monitors + +| Monitor | Seuil | Action si KO | +|---|---|---| +| `daemon-backup-ok` | Pas de ping en 25h | Alerte Slack (normal) | +| `notion-export-ok` | Pas de ping en 25h | J1 Slack normal · J2 Slack urgent + email · J3 appel téléphonique | +| `kopia-local-integrity` | Check intégrité hebdo | Slack urgent | +| `restore-test-ok` | Test restore hebdo | Slack normal si échec, urgent si 2× consécutif | + +### Cascade d'escalade (conforme [[_adn/soul]] section 2) + +| Palier | Canal | Niveau Kuma | +|---|---|---| +| Échec J1 | Slack DM | Normal | +| Échec J2 | Slack all devices ring + email | Urgent | +| Échec J3 | Appel téléphonique + tout ce qui précède | Très urgent | + +--- + +## 🖥️ Interface Kopia UI + +- **URL** : `https://kopia.daemon.jeremunlimited.com` +- **Auth** : basic auth + token header (pattern identique à Control UI OpenClaw) +- **Headers** : `X-Robots-Tag: noindex` +- **Accès** : public HTTPS ou LAN via WireGuard +- **Permissions** : lecture + restore uniquement (création snapshots bloquée en UI, seul le cron peut créer) + +Utilisations : +- Voir les snapshots passés et leur taille +- Restaurer un fichier en 2 clics +- Vérifier l'intégrité d'un snapshot +- Monitorer l'espace disque des repos + +--- + +## 🛠️ Commandes utiles (CLI) + +```bash +# Lister les snapshots locaux +kopia snapshot list + +# Restaurer la dernière version du vault +kopia snapshot restore latest /tmp/restore-vault + +# Restaurer un fichier spécifique d'un snapshot donné +kopia snapshot restore /path/to/file /tmp/restored-file + +# Vérifier l'intégrité +kopia snapshot verify + +# Voir l'espace utilisé +kopia content stats + +# Purger manuellement (suit la policy GFS) +kopia policy set --keep-latest 7 --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-annual 5 + +# Forcer un backup immédiat +sudo systemctl start daemon-backup.service +``` + +--- + +## 📝 Plan de restauration (runbook) + +### Scénario 1 : j'ai supprimé un fichier du vault + +1. Ouvrir l'UI Kopia +2. Naviguer dans le dernier snapshot → `vault/` +3. Clic droit sur le fichier → Restore → `/home/jerem/vault/` +4. `git add` + commit dans le vault + +### Scénario 2 : le VPS est HS, il faut tout reconstruire + +1. Déployer un nouveau VPS (Hetzner, même config) +2. Installer Kopia +3. Restaurer la passphrase depuis Bitwarden (ou papier) +4. Connecter Kopia au repo Google Drive (plus rapide que NAS distant) + ```bash + kopia repository connect gdrive \ + --folder-id $FOLDER_ID \ + --credentials-file /path/to/oauth.json + ``` +5. `kopia snapshot restore latest --target /` +6. Reconfigurer secrets (régénérer OAuth Google, Doppler tokens) +7. Relancer systemd : `systemctl start openclaw` + +**Temps cible de restauration complète** : < 4h (avec config nginx + wireguard + openclaw à reconfigurer). + +### Scénario 3 : compromission sécurité, besoin de rollback + +1. Identifier la date de compromission depuis les logs +2. Restaurer le snapshot de la veille (avant compromission) +3. `kopia snapshot restore --target /home/jerem/` +4. Rotation de tous les secrets (Doppler → regenerate) +5. Invalider tous les OAuth Google / Slack / Notion tokens +6. Recréer depuis zéro les tokens + +--- + +## 📐 Dimensionnement estimé + +| Donnée | Taille actuelle | Taille dans 5 ans (×10) | +|---|---|---| +| Vault Obsidian | ~10 Mo | ~100 Mo | +| Notion export mirror | ~50 Mo | ~500 Mo | +| daemon-infra | ~5 Mo | ~50 Mo | +| .openclaw config | ~2 Mo | ~20 Mo | +| /etc/* (tier 2) | ~10 Mo | ~10 Mo (stable) | +| **Total source** | **~77 Mo** | **~680 Mo** | +| **Total repo Kopia (28 snapshots + dedup + compression)** | **~200 Mo** | **~1.5 Go** | + +**Quota à demander à Fab** : 10 Go (avec marge confortable). +**Usage Google Drive** : 10 Go sur 5 TB (0.2 %). +**Usage VPS local** : ~200 Mo (7 jours de rétention, largement acceptable). + +--- + +## ❓ Points en attente + +- [ ] **Validation Fab** : autorisation de créer un dossier `Jerem Unlimited Backup DAEMON` sur le NAS + quota +- [ ] **Passphrase Kopia** : à générer et à stocker dans Bitwarden + papier +- [ ] **Secrets NAS dans Doppler** : `NAS_WEBDAV_URL`, `NAS_WEBDAV_USER`, `NAS_WEBDAV_PASS` +- [ ] **Tests de restore** : valider le scénario complet sur un VPS blank (exercice trimestriel) + +--- + +## 📚 Alternatives considérées (historique) + +| Option | Rejetée car | +|---|---| +| **Obsidian Sync officiel** | Payant, vendor lock-in, ne couvre pas Notion | +| **Backblaze B2** | Jerem a le NAS ami gratuit, pas besoin de cloud payant | +| **iCloud pour backup serveur** | Pas d'API serveur native, besoin d'un Mac allumé | +| **Restic** (vs Kopia) | Pas d'UI web — Jerem préfère avoir le visuel | +| **Borg** (vs Kopia) | Pas de backend WebDAV natif, moins polyvalent | +| **Notion → incremental seulement** | Aucun outil mature, complexité de code non justifiée vu que Kopia dedupe déjà | + +--- + +## 🔗 Références + +- [Kopia documentation](https://kopia.io/docs/) +- [Règle 3-2-1 (US-CERT)](https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf) +- [SOUL.md section alertes](/_adn/soul.md#2-règles-cardinales-non-negociables) +- Doc config VPS : [[infra/vps-config-2026-04-17]] + +--- + +*Document vivant, à mettre à jour à chaque évolution de la stratégie.*