15 KiB
| title | type | created | updated | owner | status | tags | related | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Stratégie de backup DAEMON | infra | 2026-04-18 | 2026-04-19 | jerem | ✅ déployé et opérationnel |
|
|
Stratégie de backup DAEMON — 2026-04-18
État (2026-04-19) : ✅ Déployé. 3 destinations actives (local VPS + Google Drive + NAS Ugreen). Premier run automatique via systemd timer prévu lundi 20 avril 03h00 Paris.
🎯 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 :
- VPS :
/root/.kopia-password(mode600, root-only) - Bitwarden : entrée "Kopia DAEMON backup passphrase"
- 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_URLNAS_WEBDAV_USERNAS_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)
# 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 <snapshot-id>/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
- Ouvrir l'UI Kopia
- Naviguer dans le dernier snapshot →
vault/ - Clic droit sur le fichier → Restore →
/home/jerem/vault/ git add+ commit dans le vault
Scénario 2 : le VPS est HS, il faut tout reconstruire
- Déployer un nouveau VPS (Hetzner, même config)
- Installer Kopia
- Restaurer la passphrase depuis Bitwarden (ou papier)
- Connecter Kopia au repo Google Drive (plus rapide que NAS distant)
kopia repository connect gdrive \ --folder-id $FOLDER_ID \ --credentials-file /path/to/oauth.json kopia snapshot restore latest --target /- Reconfigurer secrets (régénérer OAuth Google, Doppler tokens)
- 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
- Identifier la date de compromission depuis les logs
- Restaurer le snapshot de la veille (avant compromission)
kopia snapshot restore <snapshot-pre-compromission> --target /home/jerem/- Rotation de tous les secrets (Doppler → regenerate)
- Invalider tous les OAuth Google / Slack / Notion tokens
- 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).
✅ Déploiement effectué (2026-04-19)
- Validation Fab : dossier
Jerem Unlimited Création de contenus/DAEMON-Backupcréé - Passphrase Kopia : générée + stockée Doppler (
KOPIA_PASSPHRASE) + Bitwarden + papier - Secrets NAS Doppler :
NAS_WEBDAV_URL,NAS_WEBDAV_USER,NAS_WEBDAV_PASS(rclone-obscured) - OAuth Google unifié : nouveau client Web (Calendar + Gmail + Drive scopes)
- Repo Kopia local :
/var/backups/kopia-localactif - Sync Kopia → gdrive :
gdrive:DAEMON-Backups/kopiaactif - Sync Kopia → NAS :
nas:Jerem Unlimited Création de contenus/DAEMON-Backup/kopiaactif - Script :
/home/jerem/daemon-infra/scripts/daemon-backup.sh - Systemd timer :
daemon-backup.timer(cron 03:00 Europe/Paris, persistent=true) - Kopia UI :
https://kopia.jeremunlimited.com(basicAuth + noindex via Traefik/Coolify) - Service systemd Kopia :
kopia-server.service(port 51515 sur 0.0.0.0, UFW restreint à 10.0.0.0/8) - Monitoring Kuma : Push Monitor
DAEMON Backup, URL dans DopplerKUMA_BACKUP_PUSH_URL - Sudoers rsync :
/etc/sudoers.d/daemon-backup-rsync(jerem peut rsync /etc/* sans password)
🔜 À faire ensuite
- Test de restore réel sur VPS blank (exercice trimestriel — premier exo Q3 2026)
- Notion export (Phase 2.6) : intégration script Python notion-sdk-py + commit Gitea
daemon-notion-mirror - Monitoring sync vault Obsidian (vérifier Git push toutes les minutes ne rate pas)
🔧 Notes techniques de déploiement
TLS NAS : le certificat NAS est auto-signé (duckdns). On utilise --rclone-args=--no-check-certificate côté Kopia + no_check_certificate = true dans ~/.config/rclone/rclone.conf. Acceptable car Kopia chiffre AES-256-GCM côté client AVANT transit — TLS n'est qu'une couche additionnelle de protection contre la modification.
Préservation rclone.conf : le script daemon-backup.sh reconstruit la section [gdrive] à chaque run (avec un access_token frais), mais préserve les autres sections (notamment [nas]) via un parser awk dans le script.
Permissions /etc/* : impossible de snapshoter /etc/{systemd,nginx,wireguard} directement comme jerem (root-owned + secrets wireguard chmod 600). Solution : staging via rsync --chown=jerem:jerem vers /var/backups/etc-staging/ avant snapshot Kopia. Sudoers granulaire pour autoriser uniquement ce rsync sans password.
Docker networking : Coolify-proxy (Traefik) tourne dans Docker sur le réseau coolify (10.0.1.0/24). Pour qu'il puisse joindre Kopia server bare-metal, on bind sur 0.0.0.0:51515 puis on filtre via UFW : allow from 10.0.0.0/8 to any port 51515 (même pattern que OpenClaw 18789).
Mot de passe NAS exposé : durant le debug, j'ai dû lire ~/.config/rclone/rclone.conf du Mac de Jerem pour identifier un mismatch avec Doppler. Le mot de passe en clair (Jerem2026) a été vu. Décision Jerem : pas de rotation (mot de passe partagé Fab existant, accessible via iCloud Mac).
📚 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
- Règle 3-2-1 (US-CERT)
- SOUL.md section alertes
- Doc config VPS : _adn/infra/vps-config-2026-04-17
Document vivant, à mettre à jour à chaque évolution de la stratégie.