# Déploiement LeCoffre.io - Guide Complet **Dernière mise à jour** : 2026-03-10 **Version** : 2.0.1 Ce document consolide toute la documentation relative au déploiement (scripts, variables, logging, Nginx, SSL). --- ## 📋 Table des Matières 1. [Vue d'ensemble](#vue-densemble) 2. [Prérequis](#prérequis) 3. [Configuration](#configuration) 4. [Variables d'environnement](#variables-denvironnement) 5. [Déploiement principal](#déploiement-principal) 6. [Cartographie des checks de déploiement (source unique)](#cartographie-des-checks-de-déploiement-source-unique) 7. [Logs de déploiement](#logs-de-déploiement) 8. [Scripts et commandes](#scripts-et-commandes) 9. [Maintenance et troubleshooting](#maintenance-et-troubleshooting) 10. [API d'ancrage Bitcoin séparée](#api-dancrage-bitcoin-séparée) 11. [Sécurité](#sécurité) 12. [Monitoring](#monitoring) 13. [Disaster Recovery](#disaster-recovery) --- ## Vue d'ensemble LeCoffre.io utilise un système de déploiement automatisé via SSH orchestré depuis le **proxy** (point d’entrée unique). Le mode de déploiement recommandé est **`deploy/scripts_v2/`** (services systemd sur les serveurs d’environnements) : - Synchronisation Git - Installation des dépendances système sur l’hôte (PostgreSQL, ClamAV, Chromium, LibreOffice, Java…) - Build backend/frontend - Services `systemd` (backend/cron/frontend/router) - Migrations Prisma, injection de configuration (`system_configuration`), scripts métier (Stripe, ré-ancrage…) **Environnements disponibles** : - `test` : Environnement de test - `pprod` : Pré-production - `prod` : Production - `demo` : Démonstration --- ## Prérequis ### Sur la machine locale (déploiement) - **Git** : Pour le versioning et la synchronisation - **Node.js 25+** : Pour la compilation TypeScript - **npm** : Gestionnaire de paquets - **rsync** : Synchronisation des fichiers - **SSH avec clé configurée** : Accès au serveur distant ### Sur la machine distante (cible) - **Accès SSH avec clé** - **PostgreSQL** (service système, port 5432) - **ClamAV** (service système, port 3310) - **Chromium** (binaire `/usr/bin/chromium`) - **LibreOffice + Java** - **Node.js 25+ et npm** (pour build et exécution). Mise à jour si inférieur : `bash deploy/scripts_v2/run-update-node-25-on-servers.sh` (test, pprod, prod). ### Configuration SSH ```bash # Configurer la clé SSH ssh-copy-id -i ~/.ssh/id_ed25519 ncantu@4nk.myftp.biz # Tester la connexion ssh ncantu@4nk.myftp.biz "echo OK" ``` --- ## Configuration ### 1. Fichier `.env.` Créer `.secrets/test/.env.test`, `.secrets/pprod/.env.pprod`, ou `.secrets/prod/.env.prod` avec : ```bash # Database # Variables construites dynamiquement depuis ENV : # DATABASE_HOST=127.0.0.1 # DATABASE_PORT=5432 # DATABASE_USERNAME=lecoffre-user-${ENV} # DATABASE_NAME=bdd-${ENV} # Seule variable requise : DATABASE_PASSWORD=*** # Deployment (scripts_v2) # Les déploiements sont exécutés sur le proxy (4nk.myftp.biz / 192.168.1.100). # Les environnements sont sur le réseau privé : # - test : 192.168.1.101 → test.lecoffreio.4nkweb.com # - pprod : 192.168.1.102 → pprod.lecoffreio.4nkweb.com # - prod : 192.168.1.103 → prod.lecoffreio.4nkweb.com DEPLOY_SSH_USER=ncantu DEPLOY_SSH_KEY=~/.ssh/id_ed25519 # Frontend (sera injecté en base lors du premier déploiement) NEXT_PUBLIC_SPLASH_MESSAGE=Environnement de test # Grafana (monitoring) GRAFANA_ADMIN_USER=grafana-admin GRAFANA_ADMIN_PASSWORD=change_me ``` ### 1bis. Git (scripts_v2) `deploy/scripts_v2/deploy.sh` effectue automatiquement, **en local**, avant toute synchronisation côté cible : - `npm run lint:fix` sur `lecoffre-ressources-dev`, `lecoffre-back-main`, `lecoffre-front-main` (non bloquant) (le déploiement échoue si lint:fix retourne une erreur non corrigeable) - `git add -A` - `git commit` (message au format imposé par le dépôt) - `git push origin $DEPLOY_GIT_BRANCH` Le script est **strict** : - il exige `DEPLOY_GIT_BRANCH` (dans `.secrets//.env.` ou exporté) - la branche locale courante doit être exactement `$DEPLOY_GIT_BRANCH` - la cible est synchronisée **uniquement** sur `origin/$DEPLOY_GIT_BRANCH` (pas d’autre ref) ### 1ter. Migrations requises (scripts_v2) En mode `scripts_v2`, certaines actions **exigent** que les migrations Prisma soient exécutées dans la même commande (mode strict) : - `--resetDatabase` ⇒ **doit** être accompagné de `--migrateResolveDatabase` - `--resetDatabaseFromSchemaExport` ⇒ **doit** être accompagné de `--migrateResolveDatabase` (voir ci-dessous) - `--setSettings`, `--seedSiteTexts`, `--importStripe`, `--reanchorAll`, `--promoteSuperAdmins`, `--activateSubscriptions` ⇒ **doivent** être accompagnés de `--migrateResolveDatabase` **Variables d'automatisation (stockées en BDD via `system_configuration`) :** - `SUPERADMIN_EMAILS` : Liste d'emails (séparés par des virgules) promus automatiquement en super-admin lors du déploiement avec `--promoteSuperAdmins` - `AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS` : Liste d'emails (séparés par des virgules) dont tous les abonnements seront activés/créés automatiquement lors du déploiement avec `--activateSubscriptions` #### Baseline DB v2 depuis un export de schéma (sans rejouer l'historique des migrations) Quand les dumps disponibles sont **uniquement en v1** (et/ou que l'historique des migrations pose problème), `scripts_v2` permet de reconstruire une base **v2 vide** directement depuis un export SQL **schema-only** : - Le script applique un export SQL **schema-only** sur une base vide : - `deploy/schema-v2.sql` si présent (prioritaire) - sinon `deploy/scripts_v2/schema-v2-initial.sql` (export de référence v2 fourni dans le repo) - Puis exécute `prisma migrate resolve --applied` sur **toutes** les migrations présentes dans le repo (sans les exécuter) pour que Prisma considère la base comme "à jour" - Ensuite, `--migrateResolveDatabase` peut s'exécuter (il ne doit appliquer que des migrations futures, au-delà de la baseline) **Fichier requis :** - `deploy/schema-v2.sql` (optionnel) : export du schéma cible (schema-only) compatible `psql -f` - il peut contenir des directives `psql` (ex: `\restrict` / `\unrestrict`) : `scripts_v2` les filtre lors de l'application - si besoin, utiliser `deploy/schema-v2.sql.example` comme guide **Commande type :** ```bash bash deploy/scripts_v2/deploy.sh test \ --resetDatabaseFromSchemaExport \ --migrateResolveDatabase \ --deploy \ --skipCheckLint ``` #### Import v1 → v2 : Premier import (full) vs Imports incrémentaux (merge) **Premier import (full, destructif) :** Le flag `--importV1Data` effectue un import complet depuis un dump v1 : - Applique la compatibilité layer v1→v2 (enums + colonnes manquantes) - **TRUNCATE** toutes les tables (sauf `_prisma_migrations` et `system_configuration`) - Restaure les **TABLE DATA** du dump v1 via `pg_restore --data-only` ```bash bash deploy/scripts_v2/deploy.sh test \ --resetDatabaseFromSchemaExport \ --migrateResolveDatabase \ --importV1Data \ --deploy \ --skipCheckLint ``` **Imports incrémentaux (merge, non-destructif) :** Le flag `--importV1DataMerge` effectue un merge des données v1 dans la v2 existante : - Applique la compatibilité layer v1→v2 (enums + colonnes manquantes) - Restaure le dump v1 dans une **DB temporaire** - Effectue des **INSERT ... ON CONFLICT DO UPDATE** par table (upsert) - **Préserve** les données v2 existantes - Intègre les nouvelles données v1 ```bash # Script wrapper (recommandé) bash deploy/scripts_v2/merge-v1-data-into-v2.sh test # Ou directement bash deploy/scripts_v2/deploy.sh test \ --importV1DataMerge \ --skipCheckLint ``` **Workflow recommandé :** 1. **Premier import** : `install-or-reset-env-from-schema-export.sh ` (baseline + import full) 2. **Imports suivants** : `merge-v1-data-into-v2.sh ` (merge incrémental) **Prérequis pour les imports :** - Le dump v1 doit être présent localement : `.secrets//bdd.` - Format attendu : custom-format `pg_dump` (PGDMP) **Détails techniques (merge) :** - Les tables sans PK/UK sont **ignorées** (risque de doublons) - Les colonnes communes entre v1 et v2 sont synchronisées - Les colonnes v1 absentes en v2 sont ignorées (après compat layer) - Les colonnes v2 absentes en v1 sont préservées (non modifiées) ### 2. Base de données La base PostgreSQL doit être créée et accessible. Le script : - ✅ Applique les migrations Prisma automatiquement - ✅ Synchronise les données (IdNot, Annuaire, Stripe) - ✅ Valide les identifiants PostgreSQL avant déploiement - ❌ Ne crée PAS la base (à faire manuellement) **Validation des identifiants PostgreSQL** : Le script valide automatiquement les identifiants (`DATABASE_USERNAME` / `DATABASE_PASSWORD`) avant de démarrer le déploiement. En cas d'échec de connexion, le script affiche un message d'erreur explicite et s'arrête. **Gestion des migrations Prisma** : - Le schéma Prisma est dans `lecoffre-back-main/prisma/schema.prisma` - Les migrations sont dans `prisma/migrations/` - Le script crée automatiquement un lien symbolique `src/common/databases/migrations` → `prisma/migrations` pour que Prisma trouve les migrations - Les migrations sont appliquées via `npm run migrate` (qui utilise `prisma migrate deploy`) - Détection automatique des migrations baselinées (marquées comme appliquées sans être exécutées) et réinitialisation si nécessaire ### 3. Configuration ClamAV (system_configuration via import-env-to-db) Les variables suivantes ne vont pas dans `.env.` mais dans `.secrets//env-full--for-bdd-injection.txt` (puis importées via `config:import-env`) : ```bash CLAMAV_HOST=127.0.0.1 CLAMAV_PORT=3310 CLAMAV_SCAN_ENABLED=true CLAMAV_CONNECTION_TIMEOUT_MS=8000 CLAMAV_READ_TIMEOUT_MS=150000 CLAMAV_MAX_FILE_SIZE_MB=120 ``` > Sans ces clés, le backend refuse désormais les uploads (aucun fallback). --- ## Variables d'environnement ### Vue d'ensemble Le script `build-and-deploy.sh` lit ses configurations de déploiement depuis les fichiers `.env.` au lieu d'avoir des valeurs hardcodées. ### Variables requises Chaque fichier `.env.test`, `.env.pprod`, `.env.prod` doit contenir : #### Variables de déploiement SSH ```bash # Host SSH de la machine cible DEPLOY_SSH_HOST= # Utilisateur SSH (optionnel, défaut: debian) DEPLOY_SSH_USER=debian # Clé SSH (optionnel, défaut: ~/.ssh/id_rsa) DEPLOY_SSH_KEY=~/.ssh/id_rsa # Répertoire de déploiement sur la machine distante DEPLOY_REMOTE_PATH=/home/debian/sites/test-lecoffreio.4nkweb.com # Domaine pour Nginx et SSL DEPLOY_DOMAIN=test-lecoffreio.4nkweb.com ``` ### Configuration par environnement #### Test ```bash DEPLOY_SSH_HOST= DEPLOY_SSH_USER=debian DEPLOY_REMOTE_PATH=/home/debian/sites/test-lecoffreio.4nkweb.com DEPLOY_DOMAIN=test-lecoffreio.4nkweb.com ``` #### Pré-production ```bash DEPLOY_SSH_HOST= DEPLOY_SSH_USER=debian DEPLOY_REMOTE_PATH=/home/debian/sites/pprod-lecoffreio.4nkweb.com DEPLOY_DOMAIN=pprod-lecoffreio.4nkweb.com ``` #### Production ```bash DEPLOY_SSH_HOST= DEPLOY_SSH_USER=debian DEPLOY_REMOTE_PATH=/home/debian/sites/prod-lecoffreio.4nkweb.com DEPLOY_DOMAIN=prod-lecoffreio.4nkweb.com ``` ### Fonctionnement 1. Le script `build-and-deploy.sh` vérifie que `.env.` existe 2. Il source le fichier avec `source .env.` 3. Il mappe les variables `DEPLOY_*` vers les variables internes du script 4. Il valide que toutes les variables requises sont définies 5. Il bloque si `DEPLOY_SSH_HOST=TBD` (environnement non configuré) ### Avantages - ✅ **Pas de valeurs hardcodées** dans le script - ✅ **Configuration centralisée** dans les fichiers `.env` - ✅ **Cohérence** avec le reste de l'architecture (config en BDD) - ✅ **Facilité de maintenance** : modifier `.env.*` au lieu du script - ✅ **Sécurité** : les `.env.*` sont en `.gitignore` - ✅ **Validation** : le script vérifie que toutes les variables sont présentes --- ## Déploiement principal ### Commande simple ```bash ./deploy/scripts/build-and-deploy.sh test # Environnement test ./deploy/scripts/build-and-deploy.sh pprod # Environnement pprod ./deploy/scripts/build-and-deploy.sh prod # Environnement prod ``` ### Options de déploiement ```bash # Déploiement complet avec toutes les étapes ./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings --syncIdNot --syncDirectory # Opérations post-déploiement (conteneurs déjà actifs) ./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory --reanchorAll # Import Stripe et réancrage ./deploy/scripts/build-and-deploy.sh test --importStripe --reanchorAll # Promotion super-admins depuis liste config ./deploy/scripts/build-and-deploy.sh pprod --promoteSuperAdmins # Activation abonnements depuis liste config ./deploy/scripts/build-and-deploy.sh pprod --activateSubscriptions ``` **Flags disponibles :** - `--deploy` : Build et déploiement complet (redémarre les services systemd) - `--resetDatabase` : ⚠️ DESTRUCTIF : Recréer la base et importer depuis `.secrets//bdd.` ➜ **Important** : relancer ensuite `npm run config:import-env -- --env ` sur le serveur cible puis reseeder `role_permissions_matrix` (cf. [DATABASE_RESET_GUIDE](DATABASE_RESET_GUIDE.md)) - `--migrateResolveDatabase` : Appliquer les migrations Prisma manquantes (prisma migrate deploy) - ✅ **Vérifications systématisées** : Vérifie et ajoute automatiquement les colonnes manquantes (`proof_data`, `confirmations`, `anchor_job_id`) dans les tables d'ancrage (`document_anchors`, `document_notary_anchors`) - ✅ **8 points de vérification** : Les colonnes sont vérifiées à 8 endroits différents pour garantir leur présence - ✅ **Gestion des erreurs** : Retry automatique et messages d'erreur explicites si l'ajout de colonnes échoue - 📖 Voir [ANCRAGE_COMPLETE.md](./ANCRAGE_COMPLETE.md) pour les corrections détaillées sur les colonnes d'ancrage - `--setSettings` : Injection configurations depuis fichier env-full-* - `--seedSiteTexts` : Exécuter le seed des textes du site (`node dist/scripts/seed-site-texts.js`) - `--syncIdNot` : Synchronisation utilisateurs IdNot OAuth - `--syncDirectory` : Synchronisation API Annuaire - `--cert` : ⚠️ DESTRUCTIF : Ecrase les certificats existant, activer la gestion des certificats Let's Encrypt (sinon aucune action certificat) - `--reanchorAll` : ⚠️ DESTRUCTIF : Supprimer toutes les ancres et réancré tous les documents (tous statuts), documents notaires et RIB - ✅ **Vérification préalable** : Vérifie l'existence des tables avant d'ajouter les colonnes manquantes - ✅ **Vérification finale** : Bloque le réancrage si les colonnes indispensables (`proof_data`, `confirmations`) manquent - ✅ **Ordre garanti** : S'exécute toujours après `--migrateResolveDatabase` pour garantir la présence des colonnes - 📖 Voir [ANCRAGE_COMPLETE.md](./ANCRAGE_COMPLETE.md) pour les corrections détaillées sur les colonnes d'ancrage - `--promoteSuperAdmins` : Promotion automatique des super-admins configurés en BDD (clé SUPERADMIN_EMAILS) - `--activateSubscriptions` : Activation automatique des abonnements pour les emails configurés en BDD (clé AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS) - `--importStripe` : Synchronisation plans et abonnements Stripe - `--getToken` : Génère un couple access/refresh token pour le premier super-admin disponible (promotion automatique de `laurence@notaires.fr` si aucun super-admin actif) - `--checkLint` : Exécuter les lints/TypeScript/compilation checks avant le build (activé par défaut) - `--skipCheckLint` : Désactiver les vérifications pré-build (lint, TypeScript, compilation) - `--skipBuildChecks` : Désactiver uniquement les build checks (lint et typecheck toujours exécutés) - `--skipDiskCleanup` : Ignorer le nettoyage de l'espace disque (peut accélérer le déploiement) - `--skipBackupsRecovery` : Ignorer la récupération des sauvegardes sur la machine locale - `--aggressiveCleanup` : ⚠️ Nettoyage agressif de l'espace disque - `--showLogs` : Afficher les logs des services (backend/frontend) après le déploiement - `--showLogsService ` : Service spécifique pour --showLogs (backend, frontend, ou all, défaut: backend) - `--showLogsTail ` : Nombre de lignes de logs à afficher (défaut: 200) - `--showLogsSince ` : Filtrer les logs depuis (ex: 1h, 10m, 2024-12-02T10:00:00) #### Mise à jour des secrets *site texts* (pprod / prod) Les fichiers `.secrets//seed-site-texts-.ts` et `.secrets//env-full--for-bdd-injection.txt` ne doivent pas être versionnés dans le dépôt applicatif cible. La source de vérité est le dépôt utilisé pour déclencher le déploiement. - **Seed** : copier le contenu du seed de test vers le seed de l’environnement cible, puis adapter uniquement les mentions d’environnement (ex. retirer `[ENVIRONNEMENT DE TEST]` en prod). - **Env-full** : aligner la ligne `SITE_TEXTS_KEYS_INDEX=...` avec celle de test (même liste et même ordre) pour garantir que les clés seedées sont bien indexées. Après mise à jour des secrets, un déploiement standard (`deploy/scripts_v2/deploy.sh`) synchronise les fichiers `.secrets//` vers la cible et exécute le seed si `--seedSiteTexts` est actif. **Exemples d'usage :** ```bash # Déploiement complet environnement from scratch ./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings --syncIdNot --syncDirectory --importStripe --reanchorAll # Synchronisation quotidienne sans interruption ./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory --importStripe # Réancrage tous dossiers existants (maintenance - DESTRUCTIF) ./deploy/scripts/build-and-deploy.sh test --reanchorAll # Mise à jour code avec redéploiement ./deploy/scripts/build-and-deploy.sh pprod --deploy # Génération d'un token super-admin sans redéployer ./deploy/scripts/build-and-deploy.sh pprod --getToken # Déploiement avec affichage des logs backend ./deploy/scripts/build-and-deploy.sh pprod --deploy --showLogs --showLogsService backend --showLogsTail 500 --showLogsSince 1h ``` > ℹ️ Pour les tests manuels, il est possible de récupérer un jeton en local via `npm run token:get -- --json`. ### Processus complet Le script exécute automatiquement : #### Phase 1 : Build local 1. ✅ Compilation TypeScript de `lecoffre-ressources-dev` 2. ✅ Vérification du build (87 fichiers .js) #### Phase 2 : Synchronisation 1. ✅ Test connexion SSH 2. ✅ Création répertoire distant si nécessaire 3. ✅ Rsync de tous les fichiers (excluant node_modules, .git, logs...) 4. ✅ Transfert des fichiers `.env.` #### Phase 3 : Build distant 1. ✅ Backup base de données (pg_dump) 2. ✅ Build backend/frontend 3. ✅ Chargement variables `.env.` #### Phase 4 : Certificats SSL 1. ✅ Vérification si certificats existent 2. ✅ Génération certificat auto-signé temporaire si absent 3. ✅ Démarrage services (systemd) 4. ✅ Obtention certificat Let's Encrypt réel 5. ✅ Rechargement Nginx avec certificat #### Phase 5 : Déploiement 1. ✅ Arrêt services existants (systemd) 2. ✅ Démarrage services (systemd) 3. ✅ Attente démarrage (10s) 4. ✅ Vérification statut (systemctl) 5. ✅ Cleanup builds obsolètes #### Phase 6 : Synchronisation données (si flags activés) 1. ✅ `--setSettings` : Injection configurations depuis `env-full--for-bdd-injection.txt` - Commande utilisée côté serveur : `npm run config:import-env -- --env ` (dans le répertoire backend) - Doit être rejouée manuellement après `--resetDatabase` - ✅ Depuis 2025-12-02, le transfert des fichiers sensibles sous Windows passe par un répertoire de staging pour `Compress-Archive`, ce qui garantit que les chemins relatifs (`deploy/...`) sont bien conservés lors de l'extraction distante. 2. ✅ `--syncIdNot` : Synchronisation utilisateurs IdNot OAuth 3. ✅ `--syncDirectory` : Synchronisation offices/personnes API Annuaire 4. ✅ `--importStripe` : Synchronisation plans et abonnements Stripe 5. ✅ `--reanchorAll` : ⚠️ DESTRUCTIF : Supprimer toutes les ancres et réancrer tous les documents et dossiers 6. ✅ `--promoteSuperAdmins` : Promotion super-admins depuis liste emails 7. ✅ `--getToken` : Génération d'un access/refresh token super-admin (trace `logs/token-superadmin-*.log`) 8. ✅ Logs sauvegardés dans `logs/` #### Phase 7 : Scripts de fix (automatique) 1. ✅ **Exécution automatique** : Tous les scripts `.sh` dans `deploy/fix/` sont exécutés automatiquement après le déploiement 2. ✅ **Ordre alphabétique** : Les scripts sont exécutés dans l'ordre alphabétique 3. ✅ **Déplacement automatique** : Après exécution réussie, chaque script est déplacé dans `deploy/fixDone/` 4. ✅ **Arrêt en cas d'erreur** : Si un script échoue, le processus s'arrête et le script reste dans `deploy/fix/` 5. ✅ **Contexte complet** : Chaque script reçoit `ENV` et `DOMAIN` comme paramètres et a accès à toutes les variables d'environnement nécessaires #### Phase 8 : Vérifications finales 1. ✅ Statut services systemd 2. ✅ Health check backend (`/api/v1/public/health`) 3. ✅ Logs accessibles ### Première fois (from scratch) #### Option 1 : Script automatique ```bash # Déployer de A à Z (inclut SSL, migrations, sync) ./deploy/scripts/build-and-deploy.sh test ``` Le script détecte automatiquement que c'est un premier déploiement et : - Génère les certificats SSL - Applique toutes les migrations Prisma - Synchronise les données #### Option 2 : Script init (legacy) ```bash # Alternative : script init manuel (moins maintenu) ./deploy/scripts/init-environment.sh test admin@4nkweb.com ``` --- ## Cartographie des checks de déploiement (source unique) Cette section fait foi pour distinguer ce qui est exécuté automatiquement pendant un déploiement standard (`deploy/scripts_v2/deploy.sh`) et ce qui reste manuel. ### Snippet de renvoi standard (gabarit interne) Position attendue dans chaque document concerné : en tête du fichier, juste après le titre et les métadonnées éventuelles. Règle unique : aucun bloc local de checks de déploiement dans les autres documents. Conserver uniquement le snippet de renvoi, avec éventuellement une phrase de contexte métier non-check. Depuis un document situé dans `docs/` : ```md **Référence unique (checks de déploiement)** : [`docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique`](./DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique) ``` Depuis un document situé hors `docs/` : ```md **Référence unique (checks de déploiement)** : [`docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique`](../docs/DEPLOYMENT.md#cartographie-des-checks-de-déploiement-source-unique) ``` ### Checks automatiques (pipeline de déploiement) | Check | Déclenchement | Script source | Statut | |-------|---------------|---------------|--------| | Vérification API d'ancrage (`health` + test d'ancrage) | Systématique dans `deploy.sh` | `deploy/scripts_v2/deploy.sh` (`test_anchor_api_blocking`) | Automatique | | Migrations Prisma (`prisma generate` + `prisma migrate deploy`) | Systématique dans `deploy.sh` | `deploy/scripts_v2/remote/migrate-resolve-database.sh` | Automatique | | Build backend/frontend sur cible | Systématique en déploiement normal/import | `deploy/scripts_v2/remote/deploy-app.sh` | Automatique | | Vérification post-déploiement (health + systemd + logs récents) | Systématique après déploiement/import | `deploy/scripts_v2/_lib/git-flow.sh` (`verify_deployment_success`) | Automatique | | Lint/typecheck/build locaux | Option `--checkLint` | `deploy/scripts_v2/deploy.sh` | Optionnel | ### Scripts manuels (hors pipeline automatique) | Script | Usage | Statut | |--------|-------|--------| | `deploy/scripts_v2/run-verify-db-connection.sh` | Vérification ciblée connectivité DB | Manuel | | `deploy/scripts_v2/run-verify-invited-received-documents.sh` | Vérification SQL ciblée documents invités | Manuel | | `deploy/scripts_v2/run-check-role-permissions-matrix.sh` | Vérification droits/rôles | Manuel | | `deploy/scripts_v2/run-check-logs-and-db-invite-notaire-587.sh` | Diagnostic ciblé logs + DB | Manuel | | `deploy/scripts_v2/run-check-user-offices-logs.sh` | Diagnostic ciblé logs `UserOffices` (offices vides / sync IdNot) | Manuel | | `deploy/scripts_v2/run-copy-connectdb-if-missing.sh` | Remédiation ciblée fichier connectDB | Manuel | | `deploy/scripts_v2/run-set-settings.sh` | Exécution manuelle set-settings | Manuel | ### Scripts orphelins nettoyés - Supprimés car non appelés par le pipeline et non référencés comme étapes obligatoires : - `lecoffre-back-main/test-audit.js` - `lecoffre-back-main/test-audit.js.map` - `lecoffre-back-main/scripts/test-guest-folders-query.ts` - `lecoffre-back-main/scripts/test-guest-folders-complete.ts` --- ## Architecture (scripts_v2 - host-native) ### Vue d'ensemble Dans l’infrastructure proxy `192.168.1.100`, le SSL et le routage sont gérés **uniquement sur le proxy**. Les serveurs d’environnements (`192.168.1.101/102/103`) exposent uniquement des **ports applicatifs HTTP**. Le déploiement est orchestré par `deploy/scripts_v2/deploy.sh`. En fin d'exécution, `deploy/scripts_v2/deploy.sh` affiche l'heure de fin au format `HH:MM` pour faciliter la lecture chronologique des logs de déploiement. ### Structure des fichiers sur un serveur d’environnement ```tree /srv/4NK/test.lecoffreio.4nkweb.com/ ├── deploy/ # Scripts + fichiers de déploiement versionnés ├── deploy/scripts_v2/ # Scripts v2 (host-native) ├── lecoffre-back-main/ # Backend ├── lecoffre-front-main/ # Frontend └── lecoffre-ressources-dev/ # Ressources partagées ``` ### Services système (systemd) - `lecoffreio-backend@` - `lecoffreio-cron@` - `lecoffreio-frontend@` - `lecoffreio-router@` (port service, ex: 3009) --- ## Logs de déploiement ### Script principal `build-and-deploy.sh` Le script principal **ne produit pas automatiquement** de logs. Il faut rediriger la sortie manuellement : ```bash # Exemple recommandé ./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod.log 2>&1 ``` **Format recommandé** : `logs/build-and-deploy-.log` **Avantages de la redirection manuelle** : - Contrôle total sur le nom du fichier - Peut inclure des informations supplémentaires (date, numéro de déploiement) - Permet de gérer plusieurs logs simultanés **Exemples d'utilisation** : ```bash # Log simple ./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod.log 2>&1 # Log avec timestamp ./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod-$(date +%Y%m%d_%H%M%S).log 2>&1 # Log avec affichage en temps réel (tee) ./deploy/scripts/build-and-deploy.sh pprod --deploy 2>&1 | tee logs/build-and-deploy-pprod.log ``` ### Copie automatique vers serveur distant Le script `build-and-deploy.sh` copie automatiquement les logs de déploiement vers le serveur distant après l'exécution (succès ou échec) pour que Promtail puisse les collecter. **Fonctionnement** : - Vérifie si le fichier de log local existe - Crée le répertoire `logs/` sur le serveur distant s'il n'existe pas - Copie le log avec un nom horodaté (`build-and-deploy--YYYYMMDD-HHMMSS.log`) - Le nom correspond au pattern Promtail : `build-and-deploy-*.log` - La copie est non-bloquante (ne fait pas échouer le déploiement si elle échoue) Voir [README.md](./README.md#consolidation-operationnelle-ex-operationsmd) pour la consolidation et [ANCRAGE_COMPLETE.md](./ANCRAGE_COMPLETE.md) pour le dépannage ancrage. ### Répertoire des logs #### Structure ```text logs/ ├── build-and-deploy-pprod.log # Log principal (manuel) ├── build-and-deploy-pprod-20250102_143022.log # Log horodaté (copié automatiquement) ├── sync-idnot-20251124_143022.log # Sync IdNot (automatique) ├── sync-directory-20251124_143100.log # Sync Directory (automatique) ├── import-stripe-20251124_144000.log # Import Stripe (automatique) ├── reanchor-all-20251124_150000.log # Réancrage complet (automatique) ├── token-superadmin-20251124_151000.log # Token super-admin (automatique) └── activate-subscriptions-20251124_152000.log # Activation abonnements (automatique) ``` #### Création automatique Le répertoire `logs/` est créé automatiquement par : - `build-and-deploy.sh` (ligne 451) - `run_sync_idnot()` (ligne 853) - `run_sync_directory()` (ligne 887) ### Gestion des logs volumineux #### Compression automatique Les logs de synchronisation sont automatiquement compressés si >5MB : - Réduction à 2000 dernières lignes - Compression en `.gz` - Affichage des 20 dernières lignes après compression #### Nettoyage Les logs ne sont **pas nettoyés automatiquement**. Il est recommandé de : - Archiver les anciens logs - Supprimer les logs >30 jours - Surveiller l'espace disque **Script de nettoyage recommandé** : ```bash # Supprimer les logs >30 jours find logs/ -name "*.log" -mtime +30 -delete find logs/ -name "*.log.gz" -mtime +90 -delete ``` --- ## Scripts et commandes ### Mise à jour Node.js 25 sur test, pprod, prod Si la version de Node sur les serveurs est inférieure à 25, exécuter (depuis la machine locale, les scripts font le SSH via le proxy) : ```bash bash deploy/scripts_v2/run-update-node-25-on-servers.sh ``` Ce script copie et exécute `deploy/scripts_v2/remote/update-node-25.sh` sur chaque hôte (test, pprod, prod). Idempotent : ne modifie rien si Node >= 25. Utilise NodeSource `setup_25.x` avec repli sur `setup_current.x` si 25 n’est pas disponible. ### Scripts de déploiement #### `deploy/scripts_v2/install-or-reset-env.sh` (scripts_v2) **Bootstrap / reset complet en 1 commande (DESTRUCTIF)** pour `test` et `pprod`. Ce wrapper exécute un cycle complet : - setup host (`--setupHost`) - reset DB depuis `.secrets//bdd.` (`--resetDatabase`) - migrations Prisma (`--migrateResolveDatabase`) - build+restart (`--deploy`) - import settings en BDD (`--setSettings`) - scripts métier (`--seedSiteTexts`, `--importStripe`, `--reanchorAll`, `--promoteSuperAdmins`, `--activateSubscriptions`) ```bash # Usage bash deploy/scripts_v2/install-or-reset-env.sh test ``` #### `deploy/scripts_v2/install-or-reset-env-from-schema-export.sh` (scripts_v2) **Bootstrap / reset complet en 1 commande (DESTRUCTIF)** pour `test` et `pprod`, basé sur une **baseline schema-only** (utile quand les dumps disponibles sont uniquement en v1). Ce script enchaîne : - `--resetDatabaseFromSchemaExport` (création DB v2 vide depuis export SQL schema-only) - `--importV1Data` (import des TABLE DATA v1 dans la DB v2) - `scripts_v2` prépare automatiquement une **compat layer v1→v2** (types/colonnes manquants) en restaurant le schéma v1 dans une DB temporaire puis en appliquant le diff sur la DB v2 - `scripts_v2` n'importe pas `_prisma_migrations` (baseline Prisma gérée à part) ni `system_configuration` (géré via `--setSettings`) - `--migrateResolveDatabase` (baseline Prisma via `migrate resolve --applied` + migrations futures) - `--deploy` + scripts post-déploiement (`--setSettings`, `--seedSiteTexts`, `--importStripe`, `--reanchorAll`, `--promoteSuperAdmins`, `--activateSubscriptions`) ```bash # Usage bash deploy/scripts_v2/install-or-reset-env-from-schema-export.sh test ``` ⚠️ Pour `prod`, ce wrapper refuse d'exécuter (risque de reset DB). Utiliser `deploy/scripts_v2/deploy.sh` et valider les flags explicitement. #### `deploy/scripts_v2/merge-v1-data-into-v2.sh` (scripts_v2) **Merge incrémental v1 → v2 (NON-DESTRUCTIF)** pour `test`, `pprod` et `prod`. Ce script effectue un merge des données v1 dans la v2 existante, puis exécute les scripts post-déploiement : **Étapes du merge :** 1. Applique la compatibilité layer v1→v2 (enums + colonnes manquantes) 2. Restaure le dump v1 dans une DB temporaire 3. Effectue des upserts (INSERT ... ON CONFLICT DO UPDATE) par table 4. **Préserve** les données v2 existantes 5. Intègre les nouvelles données v1 **Scripts post-déploiement systématisés :** Après le merge, le script exécute automatiquement : - `--migrateResolveDatabase` : Applique les migrations Prisma (requis, ajouté automatiquement) - `--setSettings` : Import des configurations depuis `env-full--for-bdd-injection.txt` - `--seedSiteTexts` : Initialise les textes du site - `--importStripe` : Importe les abonnements Stripe - `--reanchorAll` : Réancrage complet des documents (DESTRUCTIF pour les ancres existantes) - `--promoteSuperAdmins` : Promotion des super-admins (via `SUPERADMIN_EMAILS` en DB) - `--activateSubscriptions` : Activation des abonnements (via `AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS` en DB) **Note :** Ces scripts sont systématisés pour garantir la cohérence des environnements après chaque merge v1→v2. ```bash # Usage bash deploy/scripts_v2/merge-v1-data-into-v2.sh test ``` **Workflow recommandé :** 1. **Premier import** : `install-or-reset-env-from-schema-export.sh ` (baseline + import full + scripts post-déploiement) 2. **Imports suivants** : `merge-v1-data-into-v2.sh ` (merge incrémental + scripts post-déploiement) **Prérequis :** - Le dump v1 doit être présent localement : `.secrets//bdd.` - Format attendu : custom-format `pg_dump` (PGDMP) **Détails techniques (merge) :** - Les tables sans PK/UK sont **ignorées** (risque de doublons) - Les colonnes communes entre v1 et v2 sont synchronisées - Les colonnes v1 absentes en v2 sont ignorées (après compat layer) - Les colonnes v2 absentes en v1 sont préservées (non modifiées) - Les lignes avec NULL dans des colonnes NOT NULL sont automatiquement filtrées #### `build-and-deploy.sh` **Script principal de déploiement complet** Déploie l'application de A à Z sur un environnement distant via SSH. ```bash # Usage ./deploy/scripts/build-and-deploy.sh [options] # Exemples ./deploy/scripts/build-and-deploy.sh test --deploy --cert --resetDatabase --setSettings ./deploy/scripts/build-and-deploy.sh pprod --syncIdNot --syncDirectory ./deploy/scripts/build-and-deploy.sh prod --deploy --importStripe --reanchorAll ``` #### `init-environment.sh` (legacy) **Initialisation d'un nouvel environnement** Alternative pour la première fois (moins maintenu que `build-and-deploy.sh`). ```bash # Usage ./deploy/scripts/init-environment.sh # Exemple ./deploy/scripts/init-environment.sh pprod nicolas.cantu@pm.me ``` **Note :** `build-and-deploy.sh` est maintenant autonome et **recommandé** pour tous les cas. #### `bump-version.sh` **Mise à jour de version** ```bash # Usage ./deploy/scripts/bump-version.sh "" # Exemple ./deploy/scripts/bump-version.sh 2.1.0 "Nouveaux exports" ``` ### Scripts de maintenance #### `cleanup-remote-disk-aggressive.sh` **Nettoyage agressif de l'espace disque** ```bash # Usage bash deploy/scripts/cleanup-remote-disk-aggressive.sh ``` **Actions effectuées** : 1. Arrêt des services systemd (backend, frontend, cron, router) 2. Nettoyage agressif (builds, caches, journaux) 3. Nettoyage des anciens builds 4. Nettoyage des caches système (apt, journaux, logs) 5. Nettoyage des caches npm et node_modules 6. Nettoyage des fichiers temporaires (/tmp, /var/tmp, builds, logs) 7. Nettoyage Git agressif (reflog, packs volumineux) 8. Affichage de l'état du disque avant et après **Précautions** : - La base de données PostgreSQL n'est pas modifiée - Les node_modules nécessaires pour le build sont préservés - Le script affiche l'état du disque avant et après le nettoyage #### `repair-remote-git.sh` **Réparation du repository Git corrompu** ```bash # Usage bash deploy/scripts/repair-remote-git.sh ``` **Cas d'utilisation** : - Erreur `BUG: diff-lib.c:633: run_diff_index must be passed exactly one tree` - Erreur `fatal: unresolved deltas left after unpacking` - Erreur `fatal: unpack-objects failed` - Erreur `invalid sha1 pointer` **Actions effectuées** : 1. Sauvegarde des fichiers sensibles (.env, nginx) 2. Nettoyage des fichiers Git verrouillés 3. Tentative de réparation avec `git fsck` et `git gc` 4. Si le repository est trop corrompu : recréation complète 5. Restauration des fichiers sensibles 6. Vérification de l'état final ### Scripts de fix automatiques #### Vue d'ensemble Les scripts de fix sont des scripts bash optionnels placés dans `deploy/fix/` qui sont exécutés automatiquement après chaque déploiement. Ils permettent d'appliquer des correctifs ponctuels ou des mises à jour de configuration sans modifier le code principal. #### Méthode de déploiement 1. **Placement** : Créer un script `.sh` dans `deploy/fix/` 2. **Exécution automatique** : Le script `build-and-deploy-local-fix.sh` est appelé automatiquement par `build-and-deploy-local.sh` après le déploiement 3. **Ordre** : Les scripts sont exécutés dans l'ordre alphabétique 4. **Déplacement** : Après exécution réussie, le script est automatiquement déplacé dans `deploy/fixDone/` #### Structure obligatoire ```bash #!/bin/bash # Description du script # Usage: Ce script est exécuté automatiquement par build-and-deploy-local-fix.sh set -e SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" DEPLOY_SCRIPTS_DIR="$(cd "$SCRIPT_DIR/../scripts" && pwd)" source "$DEPLOY_SCRIPTS_DIR/build-and-deploy-local-common.sh" ENV="$1" DOMAIN="$2" if [ -z "$ENV" ]; then error "ENV manquant" exit 1 fi if [ -z "$DOMAIN" ]; then error "DOMAIN manquant" exit 1 fi init_deploy_context "$ENV" "$DOMAIN" validate_database_credentials # Votre code ici ``` #### Règles importantes 1. **Paramètres** : Le script doit accepter `ENV` et `DOMAIN` comme paramètres 2. **Initialisation** : Utiliser `init_deploy_context` pour charger les variables d'environnement 3. **Vérifications** : Vérifier l'état des services systemd et les credentials BDD avant d'exécuter 4. **Code de retour** : Retourner `0` en cas de succès, `1` en cas d'échec 5. **Logging** : Utiliser les fonctions `info`, `success`, `error`, `warning` du script commun ### Scripts utilitaires backend #### Promotion des super-administrateurs La promotion/dé-promotion se fait via les scripts npm du backend, exécutés **sur le serveur cible** : ```bash # Sur le serveur, dans le répertoire backend npm run promote:superadmin -- --email user@notaires.fr npm run promote:superadmin -- --uid 123e4567-e89b-12d3-a456-426614174000 ``` - Le script applique automatiquement les contraintes (rechargement configuration, connexion BDD via Prisma). - L'utilisateur doit se reconnecter pour régénérer ses jetons après promotion. #### Générer un token super-admin ```bash npm run token:get -- --json ``` Ce script promeut automatiquement un super-admin si aucun n'est présent, puis génère un couple access/refresh token. #### Activation des abonnements utilisateur L'activation automatique passe par `npm run activate:subscriptions` (backend) : ```bash npm run activate:subscriptions -- user@notaires.fr ``` - Recherche par email, UID ou IdNot. - Crée un abonnement UNLIMITED si nécessaire et active ceux existants. - Fournit un résumé pour chaque office. Dans les pipelines de déploiement (`--activateSubscriptions`), cette commande est appelée automatiquement pour chaque email configuré dans `AUTO_ACTIVATE_SUBSCRIPTIONS_EMAILS`. --- ## Maintenance et troubleshooting ### Vérifications post-déploiement #### Logs ```bash # Depuis la machine distante ssh debian@ cd /home/debian/sites/test-lecoffreio.4nkweb.com # Logs temps réel journalctl -u lecoffreio-backend@ -f journalctl -u lecoffreio-frontend@ -f journalctl -u lecoffreio-cron@ -f # Logs synchronisation tail -100 logs/sync-all-*.log | grep -E "ok|error|✅|❌" ``` #### Tests ```bash # Health check curl https://test-lecoffreio.4nkweb.com/api/v1/public/health | jq # Page d'accueil curl -I https://test-lecoffreio.4nkweb.com/ # Config publique curl https://test-lecoffreio.4nkweb.com/api/v1/public/config | jq ``` - Interface Super Admin `https://test-lecoffreio.4nkweb.com/super-admin/health` - Permet de lancer des tests *live* (ancrage Signet, SMS OVH, e-mail Mailchimp, upload Pinata, lectures ID.NOT). - Chaque carte affiche le résultat détaillé : lien mempool, URL IPFS, modales JSON IdNot, confirmation "Message envoyé". - La section "Résumé base de données" reprend les volumes principaux (ex: `offices`). #### Base de données ```bash # Compter les enregistrements psql -h $DATABASE_HOST -p $DATABASE_PORT -U $DATABASE_USERNAME -d $DATABASE_NAME \ -c "SELECT 'offices' as table, COUNT(*) FROM offices UNION SELECT 'users', COUNT(*) FROM users;" ``` ### Maintenance #### Re-déploiement ```bash # Simple ./deploy/scripts/build-and-deploy.sh test # Le script : # - Détecte que SSL existe déjà → ne régénère pas # - Applique nouvelles migrations uniquement # - Re-synchronise les données ``` #### Renouvellement SSL Les certificats sont renouvelés automatiquement par Certbot (toutes les 12h). Pour forcer le renouvellement : ```bash ssh debian@ cd /home/debian/sites/test-lecoffreio.4nkweb.com # Renouvellement certificats (sur le proxy ou serveur où Certbot est installé) certbot renew # Rechargement Nginx (sur le proxy) nginx -s reload ``` #### Rollback ```bash # Restaurer backup BDD ssh debian@ cd /home/debian/sites/test-lecoffreio.4nkweb.com psql -h ... -U ... -d bdd.test < backups/bdd-test_YYYYMMDD_HHMMSS.sql # Re-déployer version précédente git checkout ./deploy/scripts/build-and-deploy.sh test ``` ### Troubleshooting #### Erreur : `Variable DEPLOY_SSH_HOST manquante` → Vérifier que `.env.` contient toutes les variables `DEPLOY_*` #### Erreur : `Impossible de se connecter` → Vérifier clé SSH : `ssh debian@` #### Erreur : Certificat Let's Encrypt échoue → Vérifier DNS : `host test-lecoffreio.4nkweb.com` → Vérifier ports : `nc -zv 80 443` #### Backend en crash loop → Vérifier logs : `ssh ... 'journalctl -u lecoffreio-backend@ -n 200'` → Vérifier BDD accessible : tester avec psql → Vérifier migrations Prisma : marquer comme appliquées si nécessaire #### Erreur : Connexion PostgreSQL impossible → Vérifier que `DATABASE_USERNAME` et `DATABASE_PASSWORD` dans `deploy/.env.` sont corrects → Vérifier que l'utilisateur PostgreSQL existe : `psql -U postgres -c "\du"` → Vérifier que l'utilisateur a les permissions sur la base : `psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE bdd-test TO lecoffre-user-test;"` #### Erreur : No migration found in prisma/migrations → Vérifier que le répertoire `prisma/migrations` existe dans le conteneur → Vérifier que le lien symbolique `src/common/databases/migrations` → `prisma/migrations` est créé → Le script crée automatiquement ce lien lors du déploiement avec `--migrateResolveDatabase` #### Erreur : Disque plein (Out of diskspace) → Utiliser le script de nettoyage : `bash deploy/scripts/cleanup-remote-disk-aggressive.sh ` → Vérifier l'espace disque : `ssh ... 'df -h'` → Le script libère généralement 15-20GB d'espace #### Erreur : Repository Git corrompu → Utiliser le script de réparation : `bash deploy/scripts/repair-remote-git.sh ` → Erreurs courantes : `unresolved deltas`, `invalid sha1 pointer`, `unpack-objects failed` → Le script sauvegarde les fichiers sensibles avant réparation #### Synchronisation échoue → Vérifier credentials IdNot dans `system_configuration` → Vérifier les logs applicatifs (API IdNot / Annuaire) côté backend #### Erreur : `curl_error` variable sans liaison (deploy.sh) **Symptômes :** `./deploy/scripts_v2/deploy.sh: ligne 281: curl_error : variable sans liaison` lorsque l'API d'ancrage échoue et que le fichier d'erreur curl est vide. **Root cause :** Avec `set -u`, toute référence à une variable non définie provoque une erreur. `curl_error` n'est défini que si le fichier d'erreur curl contient des données ; sinon la variable est utilisée sans exister. **Correctif :** Initialiser `local curl_error=""` avant usage. Fichier : `deploy/scripts_v2/deploy.sh`. ### Vérifications et debugging #### Vérifier les certificats sur le host ```bash # Sur le serveur distant ssh debian@ cd /home/debian/sites/test-lecoffreio.4nkweb.com # Lister certificats sudo ls -la deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/ # Vérifier validité sudo openssl x509 -in deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/fullchain.pem -noout -dates ``` #### Vérifier la configuration Nginx ```bash # Tester configuration (sur le host) cat deploy/nginx/nginx-test.conf # Tester configuration Nginx nginx -t # Recharger Nginx nginx -s reload ``` #### Vérifier les montages et la configuration Nginx ```bash # Voir les volumes montés # Vérifier la configuration Nginx sur le proxy nginx -T # Exemple de sortie : # /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/nginx-test.conf -> /etc/nginx/nginx.conf # /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/conf-test -> /etc/letsencrypt # /home/debian/sites/test-lecoffreio.4nkweb.com/deploy/nginx/certbot/www-test -> /var/www/certbot ``` #### Vérifier les logs ```bash # Logs Nginx (sur le proxy) journalctl -u nginx -n 50 # Logs backend (sur le serveur env) journalctl -u lecoffreio-backend@ -n 50 # Certbot : selon l'installation (cron ou service systemd) ``` --- ## API d'ancrage Bitcoin séparée L'API d'ancrage Bitcoin est déployée sur un serveur séparé. **Production** : `anchorage.certificator.4nkweb.com` (HTTPS) ### Configuration ```bash cp env.bitcoin.api.deploy.example .env.bitcoin.api.deploy nano .env.bitcoin.api.deploy # Configurer serveur Bitcoin ``` **Variables requises** : ```bash REMOTE_HOST=@ REMOTE_DIR=~/dev/lecoffre-anchor-api LOCAL_DIR=~/dev/lecoffre-anchor-api PM2_APP_NAME=lecoffre-anchor-api SSH_KEY=$HOME/.ssh/id_ed25519_4nk # Production ANCHORE_API_URL=https://anchorage.certificator.4nkweb.com ANCHORE_API_KEY= ``` ### Déploiement ```bash ./deploy-anchor-api.sh ``` ### Infrastructure - **Serveur Production** : `anchorage.certificator.4nkweb.com` (HTTPS) - **Répertoire** : `/home//dev/lecoffre-anchor-api` - **Health** : `https://anchorage.certificator.4nkweb.com/health` --- ## Sécurité ### Certificats SSL - ✅ Certificats SSL Let's Encrypt valides (renouvellement auto toutes les 12h) - ✅ Certificats en lecture seule pour Nginx - ✅ Permissions strictes sur les clés privées (600) ### Configuration - ✅ Fichiers `.env.*` en `.gitignore` - ✅ Certificats SSL Let's Encrypt valides - ✅ Configurations sensibles en BDD (masquées) - ✅ CORS strictement configuré - ✅ Rate limiting actif - ✅ Pas de ports exposés (sauf 80/443 via Nginx) ### Permissions des certificats ```bash # Les certificats doivent appartenir à root (générés par Certbot en root) sudo chown -R root:root deploy/nginx/certbot/conf-test/ # Permissions recommandées sudo chmod 755 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/ sudo chmod 644 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/fullchain.pem sudo chmod 600 deploy/nginx/certbot/conf-test/live/test-lecoffreio.4nkweb.com/privkey.pem ``` ### Lecture seule Les certificats et configurations Nginx sont configurés en **lecture seule** sur le système de fichiers. **Avantages** : - Nginx ne peut pas modifier les certificats - Séparation des privilèges --- ## Architecture récapitulative ```text ┌─────────────────────────────────────────────────────────────┐ │ HOST (Serveur distant) │ │ /home/debian/sites/test-lecoffreio.4nkweb.com/ │ │ │ │ ┌─────────────────┐ ┌──────────────────┐ │ │ │ deploy/nginx/ │ │ deploy/nginx/ │ │ │ │ nginx-test.conf │ │ certbot/ │ │ │ │ │ │ ├─ conf-test/ │ │ │ │ (Bind mount) │ │ │ └─ live/... │ │ │ └────────┬────────┘ │ └─ www-test/ │ │ │ │ │ (Bind mounts) │ │ │ │ └────────┬──────────┘ │ │ │ │ │ │ ┌────────▼────────────────────▼──────────────────────┐ │ │ │ Services (systemd / Nginx) │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Nginx │ │ Certbot │ │ │ │ │ │ (nginx:alpine│ │(certbot/ │ │ │ │ │ │ ports 80,443│ │ certbot) │ │ │ │ │ └──────┬───────┘ └──────────────┘ │ │ │ │ │ │ │ │ │ ┌──────▼───────┐ ┌──────────────┐ │ │ │ │ │ Frontend │ │ Backend │ │ │ │ │ │ (Next.js) │ │ (Express) │ │ │ │ │ │ port 3000 │ │ port 3001 │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ ┌──────────────┐ │ │ │ │ │ Cron │ │ │ │ │ │ (Tâches) │ │ │ │ │ └──────────────┘ │ │ │ │ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ Loki │ │ Promtail │ │ │ │ │ │ (port 3100) │ │ (collecte) │ │ │ │ │ └──────┬───────┘ └──────┬───────┘ │ │ │ │ │ │ │ │ │ │ ┌──────▼──────────────────▼───────┐ │ │ │ │ │ Grafana │ │ │ │ │ │ (port 3000 loopback) │ │ │ │ │ └──────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ PostgreSQL (Base de données externe) │ │ │ │ : │ │ │ └─────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────┘ ``` --- ## Commandes utiles ### Déploiement complet avec certificats ```bash # Depuis la machine de développement cd /home/debian/legacy/lecoffreio ./deploy/scripts/build-and-deploy.sh test --deploy --cert ``` ### Renouveler les certificats manuellement ```bash # Sur le serveur distant cd /home/debian/sites/test-lecoffreio.4nkweb.com # Forcer renouvellement (sur le proxy ou serveur où Certbot est installé) certbot renew --force-renewal # Recharger Nginx (sur le proxy) nginx -s reload ``` ### Vérifier l'état des services ```bash # Statut des services (sur le serveur env) systemctl status 'lecoffreio-*@*' # Logs en temps réel journalctl -u lecoffreio-backend@ -f # Health check backend curl https://test-lecoffreio.4nkweb.com/health ``` ### Logs après déploiement (depuis machine distante) ```bash ssh ncantu@ 'journalctl -u lecoffreio-backend@ -f' # Statut services ssh ncantu@ 'systemctl status "lecoffreio-*@*"' # Logs synchronisation ssh debian@ 'cd /home/debian/sites/test-lecoffreio.4nkweb.com && tail -100 logs/sync-all-*.log' # Health check curl https://test-lecoffreio.4nkweb.com/api/v1/public/health | jq ``` --- ## Monitoring ### Architecture #### Objectif - Centraliser les logs applicatifs (`logs/*.log`) via Promtail → Loki - Offrir aux équipes support un Grafana local accounts (pas de SSO) - Faciliter l'analyse racine via requêtes Loki (filtre `job`, `level`, `message`) #### Services déployés | Service | Instance | Port | Volume de données | |---------|----------|------|-------------------| | **Loki** | `lecoffre_loki_${ENV}` | 3100 (interne) | `/var/lib/lecoffre/loki-${ENV}` | | **Promtail** | `lecoffre_promtail_${ENV}` | - | `/var/lib/lecoffre/promtail-${ENV}` | | **Grafana** | `lecoffre_grafana_${ENV}` | 3000 (loopback) | `/var/lib/lecoffre/grafana-${ENV}` | #### Réseau Les services de monitoring communiquent sur l'hôte (localhost ou réseau interne). #### Flux de données ```text Backend/Cron → Fichiers logs → Promtail → Loki → Grafana ``` #### Infrastructure - **Promtail** : surveille `logs/` (bind `../logs`) via jobs `application-logs` et `sync-logs` - **Loki** : stocke les logs sur `/var/lib/lecoffre/loki-` (retention 14 jours par défaut) - **Grafana** : interface UI, accessible via `/monitor` (reverse proxy) ou tunnel SSH (`127.0.0.1:3000`) ### Configuration Grafana #### Accès **Via HTTPS (recommandé)** : 1. URL : `https:///monitor/` 2. Authentification : Identifiants configurés dans `.env.` - User : `GRAFANA_ADMIN_USER` - Password : `GRAFANA_ADMIN_PASSWORD` **Via tunnel SSH (fallback)** : ```bash ssh -L 3000:127.0.0.1:3000 debian@ ``` Puis ouvrir `http://localhost:3000` dans le navigateur. #### Variables d'environnement ```yaml GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-grafana} GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-grafana-pass} GF_SECURITY_ALLOW_EMBEDDING: "false" GF_SECURITY_DISABLE_GRAVATAR: "true" GF_USERS_ALLOW_SIGN_UP: "false" GF_SERVER_DOMAIN: ${DEPLOY_DOMAIN} GF_SERVER_ROOT_URL: "https://${DEPLOY_DOMAIN}/monitor/" GF_SERVER_SERVE_FROM_SUB_PATH: "true" ``` #### Provisioning automatique **Datasources** : **Emplacement** : `deploy/monitoring/grafana/provisioning/datasources/loki.yml` La datasource Loki est automatiquement configurée avec : - **URL** : `http://loki:3100` - **Type** : `loki` - **Accès** : `proxy` - **Par défaut** : Oui - **Max lines** : 1000 - **Derived fields** : Support pour les traceID **Dashboards** : **Emplacement** : `deploy/monitoring/grafana/provisioning/dashboards/dashboards.yml` Le provisioning des dashboards est configuré pour : - Charger automatiquement les dashboards depuis `/etc/grafana/provisioning/dashboards` - Mettre à jour toutes les 10 secondes - Permettre les mises à jour via l'UI - Organiser les dashboards par structure de dossiers #### Reverse Proxy Nginx **Fichier** : `deploy/nginx/includes/monitor.conf` Nginx configure un reverse proxy pour Grafana : - **Path** : `/monitor/` - **Backend** : `http://grafana:3000` - **Headers** : Préservation des headers X-Forwarded-* pour HTTPS - **Timeout** : 300s pour les requêtes longues ### Configuration Loki #### Fichier de configuration **Emplacement** : `deploy/monitoring/loki-config.yml` #### Paramètres clés - **Port HTTP** : 3100 (interne uniquement) - **Stockage** : Filesystem (`/var/lib/loki`) - **Rétention** : 336h (14 jours) - **Schéma** : v12 avec boltdb-shipper - **Compression** : Activée pour les réponses #### Rétention des données ```yaml table_manager: retention_deletes_enabled: true retention_period: 336h # 14 jours poll_interval: 5m ``` Les données sont automatiquement supprimées après 14 jours. ### Configuration Promtail #### Fichier de configuration **Emplacement** : `deploy/monitoring/promtail-config.yml` #### Jobs de collecte Promtail collecte les logs depuis `/var/log/lecoffre` (monté depuis `../logs` sur l'hôte) : 1. **application-logs** : Tous les fichiers `*.log` à la racine 2. **sync-logs** : Fichiers `sync-*.log` 3. **winston-logs** : Fichiers Winston avec pattern de date : - `error-YYYY-MM-DD.log` - `combined-YYYY-MM-DD.log` - `login-YYYY-MM-DD.log` 4. **deployment-logs** : Fichiers `build-and-deploy-*.log` #### Labels - `job` : Type de log (`application-logs`, `sync-logs`, `deployment-logs`) - `env` : Environnement (`test`, `pprod`, `prod`, `demo`) - ajouté via `-client.external-labels` #### Positions Les positions de lecture sont stockées dans `/var/promtail/positions.yaml` pour éviter de relire les fichiers depuis le début. ### Dashboards #### Dashboard Vue d'ensemble **Fichier** : `deploy/monitoring/grafana/provisioning/dashboards/lecoffre-overview.json` **Panneaux** : - Logs applicatifs récents + Erreurs récentes - Statistiques (1h) : Erreurs, Warnings, Connexions, Requêtes lentes - Graphiques timeseries : Erreurs/heure, Warnings/heure - Logs spécialisés : Connexion [LOGIN_MARKER], Requêtes Prisma lentes, Erreurs Prisma - Logs de synchronisation + Logs de déploiement #### Dashboards spécialisés Les dashboards suivants sont disponibles : 1. **LeCoffre.io - Backend** : Logs backend, erreurs, connexions, requêtes Prisma lentes 2. **LeCoffre.io - Frontend** : Logs frontend Next.js, erreurs, builds 3. **LeCoffre.io - Base de données** : Requêtes Prisma lentes, erreurs Prisma, erreurs connexion PostgreSQL 4. **LeCoffre.io - ClamAV Antivirus** : Scans antivirus, malwares détectés 5. **LeCoffre.io - IdNot** : Logs de connexion, synchronisation des offices 6. **LeCoffre.io - OVH/SMS** : Logs SMS, codes 2FA 7. **LeCoffre.io - Stripe** : Webhooks Stripe, abonnements 8. **LeCoffre.io - Mailchimp** : Emails envoyés, erreurs d'envoi 9. **LeCoffre.io - Bitcoin Signet** : Ancrages réussis/échoués, vérifications blockchain 10. **LeCoffre.io - Espace Tiers** : Ajouts de tiers, documents consultés 11. **LeCoffre.io - Espace Client** : Documents consultés, fichiers uploadés 12. **LeCoffre.io - Dossiers Invités** : Partages de dossiers, accès notaires invités 13. **LeCoffre.io - Espace Notaire** : Créations de dossiers, documents, ancrages ### Requêtes LogQL #### Requêtes courantes - `{job="application-logs"} |= "ERROR"` : Toutes les erreurs applicatives - `{job="sync-logs"} |= "sync-directory"` : Logs de synchronisation - `{job="application-logs"} |= "[Antivirus]"` : Tous les scans ClamAV - `{job="application-logs"} |= "[Antivirus] Malware detected"` : Malwares détectés #### Logs applicatifs généraux ```logql {job="application-logs"} ``` #### Erreurs uniquement ```logql {job="application-logs"} |~ "(ERROR|❌|error)" ``` #### Warnings ```logql {job="application-logs"} |~ "(WARN|⚠️|warn)" ``` #### Logs ClamAV ```logql {job="application-logs"} |= "[Antivirus]" ``` #### Malwares détectés ```logql {job="application-logs"} |= "[Antivirus] Malware detected" ``` #### Logs de synchronisation ```logql {job="sync-logs"} ``` #### Logs de déploiement ```logql {job="deployment-logs"} ``` #### Métriques temporelles **Nombre d'erreurs par heure** : ```logql count_over_time({job="application-logs"} |= "ERROR" [1h]) ``` **Nombre de scans ClamAV par heure** : ```logql count_over_time({job="application-logs"} |= "[Antivirus] Scan started" [1h]) ``` #### Patterns de logs utilisés - `[LOGIN_MARKER]` : Logs de connexion utilisateur - `[Prisma Slow Query]` : Requêtes Prisma lentes (> 1 seconde) - `[Prisma Error]` : Erreurs Prisma - `[Antivirus]` : Tous les logs ClamAV - `ERROR`, `❌`, `error` : Erreurs générales - `WARN`, `⚠️`, `warn` : Warnings - `✅` : Succès ### Troubleshooting Monitoring #### Problème "No Data" dans Grafana **1. Vérifier que les fichiers de logs existent** : ```bash # Sur le serveur distant ls -la /home/debian/sites/-lecoffreio.4nkweb.com/logs/ ``` **Résultat attendu** : - `backend-YYYY-MM-DD.log` (logs backend) - `cron-YYYY-MM-DD.log` (logs cron) - Autres fichiers de logs (Winston, déploiement, etc.) **2. Vérifier que Promtail peut lire les fichiers** : ```bash # Vérifier les logs Promtail (selon déploiement : systemd ou service) journalctl -u promtail -n 100 # Vérifier les positions (chemin selon installation) cat /var/lib/lecoffre/promtail-/positions.yaml # Vérifier que les fichiers de logs existent ls -la logs/ ``` **3. Vérifier la connexion Promtail → Loki** : ```bash # Vérifier que Loki est accessible (selon déploiement) curl -s http://127.0.0.1:3100/ready # Vérifier les logs Promtail pour les erreurs de connexion journalctl -u promtail -n 100 | grep -i error ``` **4. Vérifier que Loki reçoit les logs** : ```bash # Vérifier les logs Loki (selon déploiement) journalctl -u loki -n 100 # Tester l'API Loki (labels disponibles) curl -s http://127.0.0.1:3100/loki/api/v1/labels # Tester une requête LogQL curl -s "http://127.0.0.1:3100/loki/api/v1/query_range?query={job=\"application-logs\"}&limit=10" ``` **5. Vérifier les labels dans Grafana** : Dans Grafana, aller dans **Explore** (icône boussole) : 1. Sélectionner la datasource **Loki** 2. Tester la requête : `{job="application-logs"}` 3. Vérifier que des logs apparaissent **6. Vérifier la plage de temps** : Les logs doivent avoir des timestamps récents. Si les logs sont trop anciens, ils peuvent ne pas apparaître dans la plage de temps sélectionnée dans Grafana. **Solution** : Ajuster la plage de temps dans Grafana (par défaut : `now-6h` à `now`) #### Causes courantes et solutions **Cause 1 : Fichiers de logs non créés** : **Symptômes** : - `ls -la logs/` ne montre pas de fichiers `backend-*.log` ou `cron-*.log` - Les conteneurs backend/cron démarrent mais n'écrivent pas de logs **Solutions** : 1. Vérifier que les scripts wrapper sont exécutables 2. Vérifier les logs backend : `journalctl -u lecoffreio-backend@ -n 100` 3. Vérifier le répertoire des logs : `ls -la logs/` **Cause 2 : Promtail ne peut pas lire les fichiers** : **Symptômes** : - Les fichiers existent mais Promtail ne les lit pas - Erreurs `permission denied` dans les logs Promtail **Solutions** : 1. Vérifier les permissions des fichiers : `ls -la logs/` 2. Vérifier que Promtail a accès au répertoire des logs (configuration Promtail) 3. Vérifier les permissions du répertoire logs/ **Cause 3 : Promtail ne peut pas se connecter à Loki** : **Symptômes** : - Erreurs `connection refused` dans les logs Promtail - Loki ne reçoit pas de logs **Solutions** : 1. Vérifier que Loki est démarré : `systemctl status loki` ou selon déploiement 2. Vérifier que Promtail et Loki communiquent (même hôte ou URL configurée) 3. Vérifier l'URL dans `promtail-config.yml` : `http://127.0.0.1:3100/loki/api/v1/push` **Cause 4 : Labels incorrects** : **Symptômes** : - Loki reçoit des logs mais les dashboards affichent "No data" - Les requêtes LogQL ne retournent rien **Solutions** : 1. Vérifier les labels disponibles : `curl http://localhost:3100/loki/api/v1/labels` 2. Vérifier que les labels dans `promtail-config.yml` correspondent aux requêtes dans les dashboards 3. Vérifier que le label `job` est bien défini dans tous les `scrape_configs` **Cause 5 : Configuration Promtail obsolète** : **Symptôme** : Pattern trop large (`*.log`) créant des doublons **Solution** : Supprimer le `scrape_config` avec pattern trop large et conserver uniquement les configurations spécifiques (backend-*.log, cron-*.log, etc.) Voir [README.md](./README.md#consolidation-operationnelle-ex-operationsmd) et logs backend pour le dépannage Grafana/Loki. ### Persistance des données Monitoring #### Persistance des données Toutes les données sont persistées sur l'hôte dans `/var/lib/lecoffre/` : - **Loki** : `/var/lib/lecoffre/loki-${ENV}/` - Index et chunks de logs - **Promtail** : `/var/lib/lecoffre/promtail-${ENV}/` - Positions de lecture - **Grafana** : `/var/lib/lecoffre/grafana-${ENV}/` - Dashboards, datasources, utilisateurs #### Survie aux redéploiements Les répertoires de données sont créés avant le démarrage des services et survivent aux redéploiements. ### Sécurité Monitoring #### Authentification Grafana - Authentification locale uniquement - Pas d'inscription publique (`GF_USERS_ALLOW_SIGN_UP: "false"`) - Pas d'embedding externe (`GF_SECURITY_ALLOW_EMBEDDING: "false"`) #### Accès réseau - **Loki** : Accessible sur le réseau local (port 3100) - **Promtail** : Pas de port exposé (collecte uniquement) - **Grafana** : Port 3000 exposé uniquement en loopback (`127.0.0.1:3000`) #### Accès externe L'accès externe se fait uniquement via HTTPS via Nginx reverse proxy sur `/monitor/`. ### Vérification de l'état Monitoring #### Vérifier que les services sont en cours d'exécution ```bash systemctl status loki promtail grafana-server ``` #### Vérifier les logs des services ```bash # Loki journalctl -u loki -n 100 # Promtail journalctl -u promtail -n 100 # Grafana journalctl -u grafana-server -n 100 ``` #### Vérifier la connectivité Loki ```bash curl -s http://127.0.0.1:3100/ready ``` #### Vérifier les fichiers de logs collectés ```bash ls -la logs/ ``` #### Vérifier les positions Promtail ```bash cat /var/lib/lecoffre/promtail-/positions.yaml ``` --- ## Disaster Recovery ### Vue d'Ensemble Le système de disaster recovery permet de : - **Sauvegarder quotidiennement** l'état complet de la production - **Conserver 7 versions** de sauvegardes sur une VM Gandi - **Récupérer automatiquement** en cas d'incident : installation complète, bascule DNS, certificats SSL, relance des services **RTO (Recovery Time Objective)** : 3 heures **RPO (Recovery Point Objective)** : 24 heures (sauvegarde quotidienne) ### Architecture #### Infrastructure ```text Serveur Prod (192.168.1.103) │ │ [backup-daily.sh - quotidien 2h00] │ ▼ VM Gandi (92.243.24.12) │ │ /var/lecoffreio/prod/ │ ├── backup-20250109-020000.tar.gz │ ├── backup-20250108-020000.tar.gz │ ├── ... (7 versions) │ └── latest -> backup-20250109-020000.tar.gz │ ▼ [En cas d'incident] │ │ [disaster-recovery.sh] │ ▼ Serveur de Récupération (RECOVERY_TARGET_HOST) │ │ [Bascule DNS via API Gandi] │ ▼ prod.lecoffreio.4nkweb.com → Nouvelle IP ``` #### Composants 1. **`backup-daily.sh`** : Script de sauvegarde quotidienne automatique 2. **`disaster-recovery.sh`** : Script de récupération automatisée complète 3. **`gandi-dns-api.sh`** : Script d'interaction avec l'API Gandi pour la bascule DNS ### Configuration Initiale #### 1. Créer le fichier de configuration ```bash cp .secrets/.env.backup.example .secrets/.env.backup ``` #### 2. Configurer les variables Éditez `.secrets/.env.backup` : ```bash # VM Gandi (Sauvegarde) BACKUP_GANDI_HOST=92.243.24.12 BACKUP_GANDI_USER=debian BACKUP_GANDI_SSH_KEY=~/.ssh/id_ed25519 BACKUP_GANDI_PATH=/var/lecoffreio # API Gandi (Bascule DNS) GANDI_API_KEY=your-gandi-api-key-here GANDI_DOMAIN=prod.lecoffreio.4nkweb.com # Configuration de sauvegarde BACKUP_RETENTION_DAYS=7 BACKUP_SCHEDULE_HOUR=2 BACKUP_SCHEDULE_MINUTE=0 BACKUP_ENV=prod # Récupération (optionnel - pour disaster-recovery.sh) RECOVERY_TARGET_HOST=92.243.24.12 RECOVERY_TARGET_USER=debian RECOVERY_TARGET_SSH_KEY=~/.ssh/id_ed25519 ``` #### 3. Configurer l'accès SSH Assurez-vous que les clés SSH sont configurées : ```bash # Test connexion VM Gandi ssh -i ~/.ssh/id_ed25519 debian@92.243.24.12 "echo 'OK'" # Test connexion serveur de récupération (si différent) ssh -i ~/.ssh/id_ed25519 debian@$RECOVERY_TARGET_HOST "echo 'OK'" ``` #### 4. Préparer la VM Gandi Sur la VM Gandi, créer la structure de répertoires : ```bash ssh debian@92.243.24.12 sudo mkdir -p /var/lecoffreio/prod sudo chown debian:debian /var/lecoffreio/prod ``` #### 5. Vérifier l'API Gandi Tester l'accès à l'API Gandi : ```bash curl -H "Authorization: Apikey $GANDI_API_KEY" \ https://id.gandi.net/tokeninfo ``` ### Sauvegarde Quotidienne #### Exécution Manuelle ```bash ./deploy/scripts/backup/backup-daily.sh ``` #### Configuration Cron (Automatique) Sur le serveur prod, ajouter dans le crontab : ```bash # Sauvegarde quotidienne à 2h00 0 2 * * * /path/to/lecoffreio/deploy/scripts/backup/backup-daily.sh >> /path/to/logs/backup-daily.log 2>&1 ``` #### Contenu des Sauvegardes Chaque sauvegarde contient : - **`database.dump`** : Dump PostgreSQL au format custom (pg_dump -Fc) - **`.env.prod`** : Fichier de configuration de l'environnement - **`nginx-prod.conf`** : Configuration Nginx - **`certbot-conf-prod/`** : Certificats SSL (live, archive, accounts, renewal) - **`backup-metadata.json`** : Métadonnées (timestamp, Git commit, environnement) #### Structure sur VM Gandi ```text /var/lecoffreio/prod/ ├── backup-20250109-020000.tar.gz ├── backup-20250108-020000.tar.gz ├── backup-20250107-020000.tar.gz ├── backup-20250106-020000.tar.gz ├── backup-20250105-020000.tar.gz ├── backup-20250104-020000.tar.gz ├── backup-20250103-020000.tar.gz └── latest -> backup-20250109-020000.tar.gz ``` #### Rotation Automatique Le script conserve automatiquement les 7 dernières sauvegardes. Les sauvegardes plus anciennes sont supprimées automatiquement. ### Récupération d'Urgence #### Exécution ```bash # Utiliser la dernière sauvegarde (latest) ./deploy/scripts/backup/disaster-recovery.sh # Utiliser une sauvegarde spécifique ./deploy/scripts/backup/disaster-recovery.sh backup-20250108-020000.tar.gz ``` #### Processus Automatisé Le script `disaster-recovery.sh` effectue automatiquement : 1. **Récupération de la sauvegarde** depuis la VM Gandi 2. **Extraction de l'archive** et vérification du contenu 3. **Préparation du serveur de récupération** (vérification prérequis) 4. **Clone/update du repository Git** sur le serveur de récupération 5. **Restauration des fichiers de configuration** (.env, nginx, certificats) 6. **Upload du dump de base de données** 7. **Bascule DNS** via API Gandi (prod.lecoffreio.4nkweb.com → IP serveur de récupération) 8. **Attente de la propagation DNS** (vérification toutes les 30 secondes) 9. **Restauration de la base de données** sur le serveur de récupération 10. **Mise à jour des certificats SSL** (renouvellement si nécessaire) 11. **Build et déploiement** (build, démarrage services systemd) 12. **Vérification de la santé** des services (backend, nginx) 13. **Tests de connectivité** HTTP/HTTPS #### Durée Estimée - Récupération sauvegarde : ~5-10 minutes - Bascule DNS : ~5-10 minutes (propagation) - Restauration BDD : ~10-30 minutes (selon taille) - Build : ~15-30 minutes - **Total** : ~45-80 minutes (objectif RTO : 3 heures) ### Gestion DNS via API Gandi #### Script Gandi DNS API Le script `gandi-dns-api.sh` permet de gérer les enregistrements DNS : ```bash # Récupérer l'enregistrement actuel ./deploy/scripts/backup/gandi-dns-api.sh get prod.lecoffreio.4nkweb.com # Mettre à jour vers une nouvelle IP ./deploy/scripts/backup/gandi-dns-api.sh update prod.lecoffreio.4nkweb.com 92.243.24.12 # Supprimer un enregistrement (rarement nécessaire) ./deploy/scripts/backup/gandi-dns-api.sh delete prod.lecoffreio.4nkweb.com ``` #### Format de l'API L'API Gandi utilise le format : - **URL** : `https://api.gandi.net/api/v5/domains/{domain}/records/{name}/{type}` - **Authorization** : `Apikey ${GANDI_API_KEY}` - **Domain** : `lecoffreio.4nkweb.com` (domaine de base) - **Name** : `prod` (sous-domaine) - **Type** : `A` (enregistrement IPv4) ### Monitoring et Maintenance Disaster Recovery #### Vérification Quotidienne des Sauvegardes ```bash # Lister les sauvegardes sur VM Gandi ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/" # Vérifier la dernière sauvegarde ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/latest" ``` #### Logs Les scripts génèrent des logs dans `logs/` : ```bash # Logs de sauvegarde ls -lh logs/backup-daily-*.log # Logs de récupération ls -lh logs/disaster-recovery-*.log ``` #### Vérification de l'Espace Disque Sur la VM Gandi : ```bash # Espace disque utilisé ssh debian@92.243.24.12 "df -h /var/lecoffreio" # Taille des sauvegardes ssh debian@92.243.24.12 "du -sh /var/lecoffreio/prod/*" ``` #### Tests de Récupération Il est recommandé de tester la récupération **trimestriellement** : 1. Utiliser un serveur de test (ou VM temporaire) 2. Exécuter `disaster-recovery.sh` avec une sauvegarde récente 3. Vérifier que tous les services fonctionnent 4. Documenter les problèmes rencontrés ### Dépannage Disaster Recovery #### Problème : Sauvegarde échoue **Symptômes** : - Le script `backup-daily.sh` échoue - Pas de nouvelle sauvegarde dans `/var/lecoffreio/prod/` **Diagnostic** : ```bash # Vérifier les logs tail -100 logs/backup-daily-*.log # Vérifier la connexion SSH au serveur prod ssh -i ~/.ssh/id_ed25519 debian@ "echo 'OK'" # Vérifier la connexion SSH à la VM Gandi ssh -i ~/.ssh/id_ed25519 debian@92.243.24.12 "echo 'OK'" # Vérifier l'espace disque sur VM Gandi ssh debian@92.243.24.12 "df -h /var" ``` **Solutions** : - Vérifier les clés SSH - Vérifier l'espace disque disponible - Vérifier que PostgreSQL est accessible #### Problème : Récupération échoue **Symptômes** : - Le script `disaster-recovery.sh` échoue à une étape - Services non démarrés après récupération **Diagnostic** : ```bash # Vérifier les logs tail -100 logs/disaster-recovery-*.log # Vérifier l'état des services sur le serveur de récupération ssh ncantu@$RECOVERY_TARGET_HOST "systemctl status 'lecoffreio-*@*'" # Vérifier les logs ssh ncantu@$RECOVERY_TARGET_HOST "journalctl -u lecoffreio-backend@ -n 100" ``` **Solutions** : - Vérifier les prérequis (Git, Node, services systemd) sur le serveur de récupération - Vérifier l'espace disque disponible - Vérifier que le dump de base de données est valide - Vérifier la configuration DNS #### Problème : DNS non propagé **Symptômes** : - Le script indique que le DNS n'est pas propagé - Le site n'est pas accessible via HTTPS **Diagnostic** : ```bash # Vérifier l'enregistrement DNS actuel ./deploy/scripts/backup/gandi-dns-api.sh get prod.lecoffreio.4nkweb.com # Vérifier la résolution DNS dig prod.lecoffreio.4nkweb.com @8.8.8.8 # Vérifier depuis différents serveurs DNS nslookup prod.lecoffreio.4nkweb.com 8.8.8.8 nslookup prod.lecoffreio.4nkweb.com 1.1.1.1 ``` **Solutions** : - Attendre la propagation DNS (TTL peut être jusqu'à 600 secondes) - Vérifier que l'enregistrement DNS a bien été mis à jour via l'API - Vérifier les permissions de l'API Gandi #### Problème : Certificats SSL invalides **Symptômes** : - Erreur de certificat SSL lors de l'accès HTTPS - Certificats expirés **Solutions** : ```bash # Sur le serveur de récupération, régénérer les certificats ssh debian@$RECOVERY_TARGET_HOST cd /home/debian/sites/lecoffreio.4nkweb.com bash deploy/scripts/build-and-deploy-local-cert.sh prod lecoffreio.4nkweb.com ``` ### Procédures Avancées Disaster Recovery #### Restaurer une Sauvegarde Spécifique ```bash # Lister les sauvegardes disponibles ssh debian@92.243.24.12 "ls -lh /var/lecoffreio/prod/backup-*.tar.gz" # Restaurer une sauvegarde spécifique ./deploy/scripts/backup/disaster-recovery.sh backup-20250108-020000.tar.gz ``` #### Restaurer uniquement la Base de Données Si vous voulez restaurer uniquement la base de données (sans tout le reste) : ```bash # Télécharger le backup scp debian@92.243.24.12:/var/lecoffreio/prod/backup-XXXXXX.tar.gz /tmp/ # Extraire le dump tar xzf /tmp/backup-XXXXXX.tar.gz -C /tmp/extracted # Utiliser le script de reset avec le dump ./deploy/scripts/reset-and-import-database.sh prod /tmp/extracted/database.dump ``` #### Vérifier l'Intégrité d'une Sauvegarde ```bash # Télécharger le backup scp debian@92.243.24.12:/var/lecoffreio/prod/backup-XXXXXX.tar.gz /tmp/ # Extraire et vérifier tar xzf /tmp/backup-XXXXXX.tar.gz -C /tmp/extracted ls -lh /tmp/extracted/ # Vérifier le dump PostgreSQL file /tmp/extracted/database.dump # Vérifier les métadonnées cat /tmp/extracted/backup-metadata.json ``` ### Sécurité Disaster Recovery #### Protection des Clés API - Les clés API Gandi sont stockées dans `.env.backup` (fichier non versionné) - Ne jamais commiter `.env.backup` dans Git - Limiter les permissions : `chmod 600 .secrets/.env.backup` #### Chiffrement (Optionnel) Si vous souhaitez chiffrer les sauvegardes : ```bash # Chiffrer avant transfert gpg --symmetric --cipher-algo AES256 backup.tar.gz # Déchiffrer lors de la récupération gpg --decrypt backup.tar.gz.gpg > backup.tar.gz ``` ### Bonnes Pratiques Disaster Recovery 1. **Tests Réguliers** : Tester la récupération trimestriellement 2. **Monitoring** : Surveiller les logs de sauvegarde quotidienne 3. **Espace Disque** : Surveiller l'espace disque sur la VM Gandi 4. **Documentation** : Documenter toute modification du processus 5. **Validation** : Valider manuellement après chaque récupération ### Informations Validées 1. **Infrastructure VM Gandi** : - Stockage : 250GB - Machine cible : ssh debian@92.243.24.12 2. **Stratégie de sauvegarde** : - Environnement : prod uniquement - Conservation : 7 versions 3. **API Gandi** : - Clé API : Fournie (stockée dans `.env.backup`) - Permissions : Admin DNS - Domaine : prod.lecoffreio.4nkweb.com 4. **Récupération** : - RTO (Recovery Time Objective) : 3 heures - RPO (Recovery Point Objective) : 24 heures (sauvegarde quotidienne) 5. **Sécurité** : - Gestion des clés : Fichiers `.env.backup` - Chiffrement : Non requis (infrastructure privée) --- ## Références ### Documentation - **Architecture** : [ARCHITECTURE.md](./ARCHITECTURE.md) - **Reset base de données** : `docs/DATABASE_RESET_GUIDE.md` - **Scripts backend** : [SCRIPTS.md](./SCRIPTS.md) - **Monitoring** : Voir section "Monitoring" ci-dessus - **Disaster Recovery** : Voir section "Disaster Recovery" ci-dessus ### Fichiers de configuration - **Configuration systemd** : `deploy/scripts_v2/systemd/*.service` - **Configuration Nginx** : `deploy/nginx/nginx-*.conf` - **Script de déploiement** : `deploy/scripts/build-and-deploy.sh` - **Fichiers d'injection BDD** : `.secrets//env-full--for-bdd-injection.txt` ### Documentation externe - **Documentation Let's Encrypt** : - **Documentation Nginx** : --- ## Git Workflow et Versioning Voir `deploy/README.md` pour les scripts. Format des commits : **Motivations**, **Root causes**, **Correctifs**, **Evolutions**, **Pages affectées**. Hooks : `.git/hooks/commit-msg`, `.git/hooks/pre-push`. Template : `.gitmessage`. Bump version : `./deploy/scripts/bump-version.sh ""` ; met à jour `VERSION`, `package.json` (backend + frontend), génère le template splash. **Auteur des commits :** L'auteur doit être **4NK** ou **Nicolas Cantu** uniquement. Ne jamais ajouter de ligne `Co-authored-by: Cursor` ni aucune ligne Co-authored-by qui ferait apparaître un auteur autre que 4NK ou Nicolas Cantu. --- **Dernière mise à jour** : 2026-01-29 (consolidation DEPLOYMENT, MONITORING, DISASTER_RECOVERY, GIT_WORKFLOW, VERSIONING)