vault backup: 2026-04-19 17:24:28

This commit is contained in:
Jéremy BRAGATO 2026-04-19 17:24:28 +02:00
parent e3be524d7f
commit 3ac496b5fc
2 changed files with 67 additions and 8 deletions

View File

@ -2,9 +2,9 @@
title: Stratégie de backup DAEMON title: Stratégie de backup DAEMON
type: infra type: infra
created: 2026-04-18 created: 2026-04-18
updated: 2026-04-18 updated: 2026-04-19
owner: jerem owner: jerem
status: draft-en-cours-de-déploiement status: ✅ déployé et opérationnel
tags: tags:
- infra - infra
- backup - backup
@ -17,7 +17,7 @@ related:
# Stratégie de backup DAEMON — 2026-04-18 # Stratégie de backup DAEMON — 2026-04-18
> **État** : plan validé, déploiement en cours. NAS en attente de validation par Fab. > **É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.
--- ---
@ -302,12 +302,39 @@ sudo systemctl start daemon-backup.service
--- ---
## ❓ Points en attente ## ✅ Déploiement effectué (2026-04-19)
- [ ] **Validation Fab** : autorisation de créer un dossier `Jerem Unlimited Backup DAEMON` sur le NAS + quota - [x] **Validation Fab** : dossier `Jerem Unlimited Création de contenus/DAEMON-Backup` créé
- [ ] **Passphrase Kopia** : à générer et à stocker dans Bitwarden + papier - [x] **Passphrase Kopia** : générée + stockée Doppler (`KOPIA_PASSPHRASE`) + Bitwarden + papier
- [ ] **Secrets NAS dans Doppler** : `NAS_WEBDAV_URL`, `NAS_WEBDAV_USER`, `NAS_WEBDAV_PASS` - [x] **Secrets NAS Doppler** : `NAS_WEBDAV_URL`, `NAS_WEBDAV_USER`, `NAS_WEBDAV_PASS` (rclone-obscured)
- [ ] **Tests de restore** : valider le scénario complet sur un VPS blank (exercice trimestriel) - [x] **OAuth Google unifié** : nouveau client Web (Calendar + Gmail + Drive scopes)
- [x] **Repo Kopia local** : `/var/backups/kopia-local` actif
- [x] **Sync Kopia → gdrive** : `gdrive:DAEMON-Backups/kopia` actif
- [x] **Sync Kopia → NAS** : `nas:Jerem Unlimited Création de contenus/DAEMON-Backup/kopia` actif
- [x] **Script** : `/home/jerem/daemon-infra/scripts/daemon-backup.sh`
- [x] **Systemd timer** : `daemon-backup.timer` (cron 03:00 Europe/Paris, persistent=true)
- [x] **Kopia UI** : `https://kopia.jeremunlimited.com` (basicAuth + noindex via Traefik/Coolify)
- [x] **Service systemd Kopia** : `kopia-server.service` (port 51515 sur 0.0.0.0, UFW restreint à 10.0.0.0/8)
- [x] **Monitoring Kuma** : Push Monitor `DAEMON Backup`, URL dans Doppler `KUMA_BACKUP_PUSH_URL`
- [x] **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).
--- ---

View File

@ -196,3 +196,35 @@ Catégories possibles :
**Apprentissage** : accès SSH au VPS = `ssh jerem@10.66.66.1 -p 2222` (via WireGuard). Le port 22 standard n'est pas exposé sur l'interface WireGuard. **Apprentissage** : accès SSH au VPS = `ssh jerem@10.66.66.1 -p 2222` (via WireGuard). Le port 22 standard n'est pas exposé sur l'interface WireGuard.
**Implication DAEMON** : toujours utiliser port 2222 + IP WireGuard pour les commandes VPS. **Implication DAEMON** : toujours utiliser port 2222 + IP WireGuard pour les commandes VPS.
**Source** : conversation 2026-04-18 **Source** : conversation 2026-04-18
---
### 2026-04-19 — #outil — Backup stack Kopia déployée
**Contexte** : déploiement complet de la stratégie de backup ([[_adn/infra/backup-strategy-2026-04-18]]).
**Apprentissage** : Kopia + rclone installés. 3 destinations actives — local VPS (7j) + Google Drive (5 ans GFS) + NAS Ugreen Fab via WebDAV (5 ans GFS). Chiffrement AES-256-GCM client-side. Systemd timer 03h Paris. UI publique `https://kopia.jeremunlimited.com`. Push monitor Uptime Kuma. Script `/home/jerem/daemon-infra/scripts/daemon-backup.sh` orchestre tout en séquentiel avec fail-soft (un échec n'arrête pas le reste).
**Implication DAEMON** : backup quotidien automatique fonctionnel. Pour restorer un fichier : Kopia UI → snapshot → restore. CLI : `KOPIA_PASSWORD=$(doppler get KOPIA_PASSPHRASE) kopia snapshot list`. Tier 2 (`/etc/*`) snapshoté uniquement le dimanche via staging `/var/backups/etc-staging/`.
**Source** : conversation 2026-04-18 et 2026-04-19
---
### 2026-04-19 — #outil — OAuth Google unifié (1 client Web pour tout)
**Contexte** : ajout du scope Drive nécessitait nouvel OAuth client (l'ancien était type Desktop, pas compatible OAuth Playground).
**Apprentissage** : maintenant **un seul** client OAuth Google (type Web Application, nom `daemon-web`) couvre Calendar + Gmail + Drive. Refresh token unique dans Doppler (`GOOGLE_REFRESH_TOKEN`). L'ancien client Desktop a été supprimé. Tokens propagés via le script `openclaw-start.sh` (Calendar/Gmail) et `daemon-backup.sh` (Drive via rclone).
**Implication DAEMON** : pour ajouter un nouveau service Google à l'avenir, ajouter le scope sur le client Web `daemon-web` + relancer OAuth Playground pour générer un nouveau refresh token englobant tous les scopes.
**Source** : conversation 2026-04-19
---
### 2026-04-19 — #pattern — Sécurité : ne pas écraser les configs partagées
**Contexte** : le script backup écrasait `~/.config/rclone/rclone.conf` à chaque run pour rafraîchir le token gdrive, ce qui supprimait la section `[nas]` créée séparément.
**Apprentissage** : quand un script reconstruit un fichier de config partagé, il faut **préserver les sections étrangères**. Pattern à appliquer ailleurs : avant tout `cat > config_file`, vérifier si le fichier contient des sections que le script ne gère pas et les réinjecter.
**Implication DAEMON** : pour toute modification de config multi-section (rclone, openclaw, nginx, etc.) → soit edit ciblé in-place, soit reconstruction préservant l'existant.
**Source** : conversation 2026-04-19
---
### 2026-04-19 — #relation — Fab autorisé pour backup NAS
**Contexte** : Fab (collaborateur vidéo + ami) a accepté que le NAS Ugreen serve aussi pour les backups DAEMON.
**Apprentissage** : dossier `Jerem Unlimited Création de contenus/DAEMON-Backup/` sur le NAS contient les blobs Kopia chiffrés (Fab ne peut PAS les lire sans la passphrase Kopia). Mot de passe WebDAV partagé `Jerem2026` (sans rotation pour ne pas casser le workflow Mac existant).
**Implication DAEMON** : Fab reste un partenaire de confiance technique sans accès aux données Jerem (chiffrement client-side garantit la confidentialité). Pour les autres tiers, **toujours chiffrer avant transit** vers leurs infras.
**Source** : conversation 2026-04-19