Migration G9 — Kit d'exécution
Objectif : tout le matériel (scripts + configs + compose) prêt à exécuter la migration
xpenology → G9, phase par phase, quand le G9 sera branché (IP temporaire .24).
Règle d'or : chaque script est idempotent et sécurisé. Les opérations destructives (partitionnement, LUKS, wipe) sont bloquées sans le drapeau
--i-understandet la validation explicite de l'utilisateur (garde-fou G3).
Charte d'autonomie (garde-fous G1–G10)
| # | Garde-fou |
|---|---|
| G1 | Lecture seule libre ; toute modif délibérée et documentée. |
| G2 | Aucune modif de données sans backup vérifié en place. |
| G3 | Op. destructives (rm -rf, mkfs, wipe, dd, partition, RAID/LUKS, suppression conteneur) = validation explicite avant exécution. |
| G4 | Double-run : xpenology = source de vérité ; aucune suppression dessus tant que le contrepartie G9 n'est pas validé. |
| G5 | IP G9 = .24 tant que le xpenology n'est pas décommissionné. |
| G6 | Aucun changement réseau impactant d'autres appareils sans validation. |
| G7 | Chaque modif a un rollback documenté. |
| G8 | Journalisation de chaque action (quoi, pourquoi, résultat). |
| G9 | Aucun secret loggué ou commité. |
| G10 | Périmètre = G9 (+ lecture xpenology) ; autres machines sur validation. |
Correspondance garde-fou → point d'application
| Garde-fou | Point d'application |
|---|---|
| G1 | Scripts idempotents, en-têtes documentant chaque modification. |
| G2 | 06-restic-backup.sh : backup + test de restauration avant toute migration. |
| G3 | 06b-usb-media.sh, 08-decommission.sh : drapeau --i-understand + saisie du nom du disque / WIPE XPENOLOGY. |
| G4 | 07a–07d (+ 07-migrate-stateful.sh générique) : lecture seule du xpenology + intégrité sha256 ; 08-decommission.sh exige la validation de toutes les briques avant wipe. |
| G5 | README (ordre d'exécution) + 08-decommission.sh : IP .24→.25 uniquement au décommissionnement. |
| G6 | 01-hardening.sh : ufw LAN-only (192.168.1.0/24), pas d'exposition WAN. |
| G7 | Chaque script : section Rollback en en-tête + colonne Rollback du journal. |
| G8 | journal() de chaque script → journal.md (6 colonnes : date, phase, action, raison, résultat, rollback). |
| G9 | .gitignore (*.env, secrets/, configs remplis) + 03b-secrets.sh (chmod 600, non loggué). |
| G10 | Scripts ne modifient que le G9 ; xpenology en lecture seule (SSH Master@192.168.1.25:222, clé SSH — compte effi bloqué par Synology 10/2026). |
Arborescence
g9-migration/
├── README.md ← ce fichier (runbook)
├── journal.md ← journal d'exécution (G8) — à remplir pendant la migration
├── scripts/
│ ├── 01-hardening.sh ← T2.1 : SSH keys, ufw (LAN-only), unattended-upgrades, fail2ban
│ ├── 02-data.sh ← T2.2 : espace /data (NON destructif — LUKS abandonné 10/10/2026)
│ ├── 03-docker.sh ← T2.3 : Docker + compose + groupe docker
│ ├── 03b-secrets.sh ← T2.3b : bootstrap des fichiers secrets des briques (chmod 600)
│ ├── 04-smb.sh ← T2.4 : partage SMB (données famille)
│ ├── 05-beszel.sh ← T2.5 : agent Beszel
│ ├── 06-restic-backup.sh ← T3.1 : restic G9 → Freebox + test restauration
│ ├── 06b-usb-media.sh ← T6.1 : montage des disques USB média → /mnt/usb-media
│ ├── 06c-postboot-check.sh ← contrôles post-reboot (lecture seule, 15+ checks)
│ ├── 07-migrate-stateful.sh← T4.x : générique (rsync) — INOPÉRANT sur le DSM : sshd
│ │ refuse `rsync --server` et scp → utiliser 07a–07d
│ ├── 07a-migrate-gitea.sh ← T4.4 : Gitea + backend Postgres (transport tar sur SSH)
│ ├── 07b-migrate-vaultwarden.sh ← T4.1 : Vaultwarden (coffre + 2FA + ADMIN_TOKEN)
│ ├── 07c-migrate-nextcloud.sh ← T4.2 : Nextcloud + MariaDB + Collabora
│ ├── 07d-migrate-photoprism.sh ← T4.3 : PhotoPrism (copie 530 Go + indexation)
│ ├── restic-notify.sh ← alerte Matrix des jobs restic (posée par 06)
│ └── 08-decommission.sh ← T6.4 : décommissionnement xpenology [DESTRUCTIF]
├── compose/ ← docker-compose.yml versionnés (stockés aussi dans Gitea)
│ ├── vaultwarden/ ← T4.1
│ ├── nextcloud/ ← T4.2
│ ├── photoprism/ ← T4.3
│ ├── gitea/ ← T4.4
│ ├── n8n/ ← T4.5
│ ├── jellyfin/ ← T6.2
│ └── watchtower/ ← S11.4 : Watchtower sélectif
└── configs/
├── fail2ban.local.conf ← config fail2ban (T2.1)
└── restic.env.example ← template restic (T3.1) — REMPLIR les secrets
Ordre d'exécution (phase par phase)
| Phase | Script / action | Garde-fou |
|---|---|---|
| 1 | (xpenology) exclure stateful de Watchtower + inventaire | G4 |
| 2 | 01-hardening.sh → 02-data.sh → 03-docker.sh → 03b-secrets.sh → 04-smb.sh → 05-beszel.sh |
— |
| 3 | 06-restic-backup.sh (backup + test restauration) |
G2 |
| 4 | par brique, dans l'ordre — après 03b-secrets.sh : 07b-migrate-vaultwarden.sh (T4.1) → 07c-migrate-nextcloud.sh (T4.2) → 07d-migrate-photoprism.sh (T4.3) → 07a-migrate-gitea.sh (T4.4) → n8n (T4.5) → DNS/TLS (T4.6). 07-migrate-stateful.sh = script générique rsync, inopérant sur le DSM (sshd refuse rsync --server/scp) ; transport réel des 07a–07d = tar sur SSH |
G4 |
| 5 | restic 3-2-1 complet (G9 + PC IA → Freebox → 218play) | G2 |
| 6 | 06b-usb-media.sh (T6.1) → Jellyfin (T6.2) → IP .24→.25 → 08-decommission.sh |
G3, G4, G5 |
| 7 | (G7) wipe DSM + Ubuntu neuf + boot test | G3, G10 |
Note disque (décision 10/10/2026 — Option 0) : le G9 est mono-disque (Samsung 990 Pro 2 To, seul disque interne, aucun RAID prévu).
02-data.shcrée l'espace/dataen simple dossier sur le LV racine existant : ni partitionnement, ni LUKS, ni réinstallation (LUKS abandonné — données familiales non critiques ; protection = ufw LAN-only + backups restic chiffrés, voirDOSSIER-SOFTWARE.mdS9/S10 changelog 10/10/2026). La tolérance panne disque est assurée par le 3-2-1 (Phases 3/5) et le spare G7 (Phase 7).
Phase 3 — backup restic : état au 10/10/2026
Repo rclone:freeboxftp:Freebox/backup/g9 (Freebox Delta, partage Save/Freebox,
1.79 To, 1.785 To libres). Snapshot initial 21de0787 : 4 564 fichiers,
6.956 GiB lus / 4.178 GiB stockés (sources /data, /home/folzo, /etc).
- Transport & append-only : backend rclone de restic, remote FTP local
freeboxftp:= 192.168.1.254:21 (SMBfreebox:en secours), aucun montage ; append-only prouvé. Transports testés/écartés et limitations : source unique →RESTORE-G9.md§6. - Test de restauration : fichier restauré depuis la Freebox, sha256 identique
(
9352a905d9bb…, 470 637 o, restore < 2 s) — voirRESTORE-G9.md§2/§5 etjournal.md. - Automatisation (cron root, logs
/var/log/restic-*.log) : 03:30 backup (conteneurs stateful stoppés ~1–3 min : valheim, n8n, synapse, couchdb, obsidian), 04:00 prune (7 quotidiens / 4 hebdo / 12 mensuels / 5 annuels), 09:15 health (alerte si snapshot > 26 h). Les 2 jobs ont été lancés à la main (rc=0, snapshotcccdb2c7). - Alerte Matrix : directe via Synapse (
/etc/restic/matrix.env, token ops-bot, salon ops) — testée, messages réellement reçus. Voie de secours webhook n8n conservée (RESTIC_NOTIFY_WEBHOOK) ; accès n8n à recréer (clé API à générer dans l'UI). - Persistance post-reboot : validée par un vrai reboot (21:36) —
scripts/06c-postboot-check.sh= 15 contrôles OK / 0 KO (binaires, env/clé/config en 600, aucun montage requis, cron, jobs, repo lisible +checkOK, conteneurs relancés). À rejouer après tout changement. - Secrets :
/etc/restic/repo.key(clé du repo, jamais affichée — à consigner dans Vaultwarden, item « G9 – clé repo restic »),/etc/restic/cifs.cred,/etc/restic/matrix.env,/root/.config/rclone/{rclone,ftp}.conf,/etc/restic.env→ tous600root ; aucun secret dans le repo git (.gitignore:*.env,*.cred,*.key).
Convention
- Chaque script affiche ce qu'il fait, est idempotent, et écrit dans
journal.md. - Les secrets (mots de passe, clés restic) vont dans
configs/*.envhors git (G9). - Un script échoue → il s'arrête (
set -euo pipefail) → on lit le journal → on corrige.