**Motivations:** - Align master with current codebase (token from projects/<id>/.secrets/<env>/ia_token) - Id resolution by mail To or by API token; no slug **Root causes:** - Token moved from conf.json to .secrets/<env>/ia_token; env from directory name **Correctifs:** - Server and scripts resolve project+env by scanning all projects and envs **Evolutions:** - tickets-fetch-inbox routes by To address; notary-ai agents and API doc updated **Pages affectées:** - ai_working_help/server.js, docs, project_config.py, lib/project_config.sh - projects/README.md, lecoffreio/docs/API.md, gitea-issues/tickets-fetch-inbox.py
80 KiB
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
- Vue d'ensemble
- Prérequis
- Configuration
- Variables d'environnement
- Déploiement principal
- Cartographie des checks de déploiement (source unique)
- Logs de déploiement
- Scripts et commandes
- Maintenance et troubleshooting
- API d'ancrage Bitcoin séparée
- Sécurité
- Monitoring
- 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 testpprod: Pré-productionprod: Productiondemo: 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
# 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.<env>
Créer .secrets/test/.env.test, .secrets/pprod/.env.pprod, ou .secrets/prod/.env.prod avec :
# 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:fixsurlecoffre-ressources-dev,lecoffre-back-main,lecoffre-front-main(non bloquant) (le déploiement échoue si lint:fix retourne une erreur non corrigeable)git add -Agit 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>/.env.<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--promoteSuperAdminsAUTO_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.sqlsi 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 --appliedsur toutes les migrations présentes dans le repo (sans les exécuter) pour que Prisma considère la base comme "à jour" - Ensuite,
--migrateResolveDatabasepeut 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) compatiblepsql -f- il peut contenir des directives
psql(ex:\restrict/\unrestrict) :scripts_v2les filtre lors de l'application - si besoin, utiliser
deploy/schema-v2.sql.examplecomme guide
- il peut contenir des directives
Commande type :
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_migrationsetsystem_configuration) - Restaure les TABLE DATA du dump v1 via
pg_restore --data-only
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
# 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é :
- Premier import :
install-or-reset-env-from-schema-export.sh <env>(baseline + import full) - Imports suivants :
merge-v1-data-into-v2.sh <env>(merge incrémental)
Prérequis pour les imports :
- Le dump v1 doit être présent localement :
.secrets/<env>/bdd.<env> - 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/migrationspour que Prisma trouve les migrations - Les migrations sont appliquées via
npm run migrate(qui utiliseprisma 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.<env> mais dans .secrets/<env>/env-full-<env>-for-bdd-injection.txt (puis importées via config:import-env) :
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.<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
# Host SSH de la machine cible
DEPLOY_SSH_HOST=<IP_SERVEUR>
# 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
DEPLOY_SSH_HOST=<IP_SERVEUR_TEST>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/test-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=test-lecoffreio.4nkweb.com
Pré-production
DEPLOY_SSH_HOST=<IP_SERVEUR_PPROD>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/pprod-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=pprod-lecoffreio.4nkweb.com
Production
DEPLOY_SSH_HOST=<IP_SERVEUR_PROD>
DEPLOY_SSH_USER=debian
DEPLOY_REMOTE_PATH=/home/debian/sites/prod-lecoffreio.4nkweb.com
DEPLOY_DOMAIN=prod-lecoffreio.4nkweb.com
Fonctionnement
- Le script
build-and-deploy.shvérifie que.env.<env>existe - Il source le fichier avec
source .env.<env> - Il mappe les variables
DEPLOY_*vers les variables internes du script - Il valide que toutes les variables requises sont définies
- 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
./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
# 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/<ENV>/bdd.<ENV>➜ Important : relancer ensuitenpm run config:import-env -- --env <env>sur le serveur cible puis reseederrole_permissions_matrix(cf. DATABASE_RESET_GUIDE) -
--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 pour les corrections détaillées sur les colonnes d'ancrage
- ✅ Vérifications systématisées : Vérifie et ajoute automatiquement les colonnes manquantes (
-
--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
--migrateResolveDatabasepour garantir la présence des colonnes - 📖 Voir 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 delaurence@notaires.frsi 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 <name>: Service spécifique pour --showLogs (backend, frontend, ou all, défaut: backend) -
--showLogsTail <lines>: Nombre de lignes de logs à afficher (défaut: 200) -
--showLogsSince <duration>: Filtrer les logs depuis (ex: 1h, 10m, 2024-12-02T10:00:00)
Mise à jour des secrets site texts (pprod / prod)
Les fichiers .secrets/<env>/seed-site-texts-<env>.ts et .secrets/<env>/env-full-<env>-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/<env>/ vers la cible et exécute le seed si --seedSiteTexts est actif.
Exemples d'usage :
# 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
- ✅ Compilation TypeScript de
lecoffre-ressources-dev - ✅ Vérification du build (87 fichiers .js)
Phase 2 : Synchronisation
- ✅ Test connexion SSH
- ✅ Création répertoire distant si nécessaire
- ✅ Rsync de tous les fichiers (excluant node_modules, .git, logs...)
- ✅ Transfert des fichiers
.env.<env>
Phase 3 : Build distant
- ✅ Backup base de données (pg_dump)
- ✅ Build backend/frontend
- ✅ Chargement variables
.env.<env>
Phase 4 : Certificats SSL
- ✅ Vérification si certificats existent
- ✅ Génération certificat auto-signé temporaire si absent
- ✅ Démarrage services (systemd)
- ✅ Obtention certificat Let's Encrypt réel
- ✅ Rechargement Nginx avec certificat
Phase 5 : Déploiement
- ✅ Arrêt services existants (systemd)
- ✅ Démarrage services (systemd)
- ✅ Attente démarrage (10s)
- ✅ Vérification statut (systemctl)
- ✅ Cleanup builds obsolètes
Phase 6 : Synchronisation données (si flags activés)
- ✅
--setSettings: Injection configurations depuisenv-full-<env>-for-bdd-injection.txt- Commande utilisée côté serveur :
npm run config:import-env -- --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.
- Commande utilisée côté serveur :
- ✅
--syncIdNot: Synchronisation utilisateurs IdNot OAuth - ✅
--syncDirectory: Synchronisation offices/personnes API Annuaire - ✅
--importStripe: Synchronisation plans et abonnements Stripe - ✅
--reanchorAll: ⚠️ DESTRUCTIF : Supprimer toutes les ancres et réancrer tous les documents et dossiers - ✅
--promoteSuperAdmins: Promotion super-admins depuis liste emails - ✅
--getToken: Génération d'un access/refresh token super-admin (tracelogs/token-superadmin-*.log) - ✅ Logs sauvegardés dans
logs/
Phase 7 : Scripts de fix (automatique)
- ✅ Exécution automatique : Tous les scripts
.shdansdeploy/fix/sont exécutés automatiquement après le déploiement - ✅ Ordre alphabétique : Les scripts sont exécutés dans l'ordre alphabétique
- ✅ Déplacement automatique : Après exécution réussie, chaque script est déplacé dans
deploy/fixDone/ - ✅ Arrêt en cas d'erreur : Si un script échoue, le processus s'arrête et le script reste dans
deploy/fix/ - ✅ Contexte complet : Chaque script reçoit
ENVetDOMAINcomme paramètres et a accès à toutes les variables d'environnement nécessaires
Phase 8 : Vérifications finales
- ✅ Statut services systemd
- ✅ Health check backend (
/api/v1/public/health) - ✅ Logs accessibles
Première fois (from scratch)
Option 1 : Script automatique
# 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)
# 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/ :
**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/ :
**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.jslecoffre-back-main/test-audit.js.maplecoffre-back-main/scripts/test-guest-folders-query.tslecoffre-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
/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@<domain>lecoffreio-cron@<domain>lecoffreio-frontend@<domain>lecoffreio-router@<domain>(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 :
# Exemple recommandé
./deploy/scripts/build-and-deploy.sh pprod --deploy > logs/build-and-deploy-pprod.log 2>&1
Format recommandé : logs/build-and-deploy-<env>.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 :
# 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-<env>-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 pour la consolidation et ANCRAGE_COMPLETE.md pour le dépannage ancrage.
Répertoire des logs
Structure
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é :
# 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 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/<env>/bdd.<env>(--resetDatabase) - migrations Prisma (
--migrateResolveDatabase) - build+restart (
--deploy) - import settings en BDD (
--setSettings) - scripts métier (
--seedSiteTexts,--importStripe,--reanchorAll,--promoteSuperAdmins,--activateSubscriptions)
# 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_v2pré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 v2scripts_v2n'importe pas_prisma_migrations(baseline Prisma gérée à part) nisystem_configuration(géré via--setSettings)
--migrateResolveDatabase(baseline Prisma viamigrate resolve --applied+ migrations futures)--deploy+ scripts post-déploiement (--setSettings,--seedSiteTexts,--importStripe,--reanchorAll,--promoteSuperAdmins,--activateSubscriptions)
# 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 :
- Applique la compatibilité layer v1→v2 (enums + colonnes manquantes)
- Restaure le dump v1 dans une DB temporaire
- Effectue des upserts (INSERT ... ON CONFLICT DO UPDATE) par table
- Préserve les données v2 existantes
- 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 depuisenv-full-<env>-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 (viaSUPERADMIN_EMAILSen DB)--activateSubscriptions: Activation des abonnements (viaAUTO_ACTIVATE_SUBSCRIPTIONS_EMAILSen DB)
Note : Ces scripts sont systématisés pour garantir la cohérence des environnements après chaque merge v1→v2.
# Usage
bash deploy/scripts_v2/merge-v1-data-into-v2.sh test
Workflow recommandé :
- Premier import :
install-or-reset-env-from-schema-export.sh <env>(baseline + import full + scripts post-déploiement) - Imports suivants :
merge-v1-data-into-v2.sh <env>(merge incrémental + scripts post-déploiement)
Prérequis :
- Le dump v1 doit être présent localement :
.secrets/<env>/bdd.<env> - 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.
# Usage
./deploy/scripts/build-and-deploy.sh <ENV> [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).
# Usage
./deploy/scripts/init-environment.sh <ENV> <EMAIL>
# 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
# Usage
./deploy/scripts/bump-version.sh <VERSION> "<MESSAGE>"
# 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
# Usage
bash deploy/scripts/cleanup-remote-disk-aggressive.sh <ENV>
Actions effectuées :
- Arrêt des services systemd (backend, frontend, cron, router)
- Nettoyage agressif (builds, caches, journaux)
- Nettoyage des anciens builds
- Nettoyage des caches système (apt, journaux, logs)
- Nettoyage des caches npm et node_modules
- Nettoyage des fichiers temporaires (/tmp, /var/tmp, builds, logs)
- Nettoyage Git agressif (reflog, packs volumineux)
- 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
# Usage
bash deploy/scripts/repair-remote-git.sh <ENV>
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 :
- Sauvegarde des fichiers sensibles (.env, nginx)
- Nettoyage des fichiers Git verrouillés
- Tentative de réparation avec
git fscketgit gc - Si le repository est trop corrompu : recréation complète
- Restauration des fichiers sensibles
- 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
- Placement : Créer un script
.shdansdeploy/fix/ - Exécution automatique : Le script
build-and-deploy-local-fix.shest appelé automatiquement parbuild-and-deploy-local.shaprès le déploiement - Ordre : Les scripts sont exécutés dans l'ordre alphabétique
- Déplacement : Après exécution réussie, le script est automatiquement déplacé dans
deploy/fixDone/
Structure obligatoire
#!/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
- Paramètres : Le script doit accepter
ENVetDOMAINcomme paramètres - Initialisation : Utiliser
init_deploy_contextpour charger les variables d'environnement - Vérifications : Vérifier l'état des services systemd et les credentials BDD avant d'exécuter
- Code de retour : Retourner
0en cas de succès,1en cas d'échec - Logging : Utiliser les fonctions
info,success,error,warningdu 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 :
# 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
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) :
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
# Depuis la machine distante
ssh debian@<IP_SERVEUR>
cd /home/debian/sites/test-lecoffreio.4nkweb.com
# Logs temps réel
journalctl -u lecoffreio-backend@<domain> -f
journalctl -u lecoffreio-frontend@<domain> -f
journalctl -u lecoffreio-cron@<domain> -f
# Logs synchronisation
tail -100 logs/sync-all-*.log | grep -E "ok|error|✅|❌"
Tests
# 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
# 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
# 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 :
ssh debian@<IP_SERVEUR>
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
# Restaurer backup BDD
ssh debian@<IP_SERVEUR>
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 <commit-hash>
./deploy/scripts/build-and-deploy.sh test
Troubleshooting
Erreur : Variable DEPLOY_SSH_HOST manquante
→ Vérifier que .env.<env> contient toutes les variables DEPLOY_*
Erreur : Impossible de se connecter
→ Vérifier clé SSH : ssh debian@<IP_SERVEUR>
Erreur : Certificat Let's Encrypt échoue
→ Vérifier DNS : host test-lecoffreio.4nkweb.com
→ Vérifier ports : nc -zv <IP_SERVEUR> 80 443
Backend en crash loop
→ Vérifier logs : ssh ... 'journalctl -u lecoffreio-backend@<domain> -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.<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 <env>
→ 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 <env>
→ 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
# Sur le serveur distant
ssh debian@<IP_SERVEUR>
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
# 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
# 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
# Logs Nginx (sur le proxy)
journalctl -u nginx -n 50
# Logs backend (sur le serveur env)
journalctl -u lecoffreio-backend@<domain> -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
cp env.bitcoin.api.deploy.example .env.bitcoin.api.deploy
nano .env.bitcoin.api.deploy # Configurer serveur Bitcoin
Variables requises :
REMOTE_HOST=<USER>@<IP_SERVEUR_BITCOIN>
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=<CLE_API>
Déploiement
./deploy-anchor-api.sh
Infrastructure
- Serveur Production :
anchorage.certificator.4nkweb.com(HTTPS) - Répertoire :
/home/<USER>/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
# 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
┌─────────────────────────────────────────────────────────────┐
│ 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) │ │
│ │ <IP_POSTGRESQL>:<PORT_POSTGRESQL> │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Commandes utiles
Déploiement complet avec certificats
# Depuis la machine de développement
cd /home/debian/legacy/lecoffreio
./deploy/scripts/build-and-deploy.sh test --deploy --cert
Renouveler les certificats manuellement
# 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
# Statut des services (sur le serveur env)
systemctl status 'lecoffreio-*@*'
# Logs en temps réel
journalctl -u lecoffreio-backend@<domain> -f
# Health check backend
curl https://test-lecoffreio.4nkweb.com/health
Logs après déploiement (depuis machine distante)
ssh ncantu@<IP_SERVEUR> 'journalctl -u lecoffreio-backend@<domain> -f'
# Statut services
ssh ncantu@<IP_SERVEUR> 'systemctl status "lecoffreio-*@*"'
# Logs synchronisation
ssh debian@<IP_SERVEUR> '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
Backend/Cron → Fichiers logs → Promtail → Loki → Grafana
Infrastructure
- Promtail : surveille
logs/(bind../logs) via jobsapplication-logsetsync-logs - Loki : stocke les logs sur
/var/lib/lecoffre/loki-<env>(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é) :
- URL :
https://<DEPLOY_DOMAIN>/monitor/ - Authentification : Identifiants configurés dans
.env.<env>- User :
GRAFANA_ADMIN_USER - Password :
GRAFANA_ADMIN_PASSWORD
- User :
Via tunnel SSH (fallback) :
ssh -L 3000:127.0.0.1:3000 debian@<DEPLOY_SSH_HOST>
Puis ouvrir http://localhost:3000 dans le navigateur.
Variables d'environnement
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
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) :
- application-logs : Tous les fichiers
*.logà la racine - sync-logs : Fichiers
sync-*.log - winston-logs : Fichiers Winston avec pattern de date :
error-YYYY-MM-DD.logcombined-YYYY-MM-DD.loglogin-YYYY-MM-DD.log
- 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 :
- LeCoffre.io - Backend : Logs backend, erreurs, connexions, requêtes Prisma lentes
- LeCoffre.io - Frontend : Logs frontend Next.js, erreurs, builds
- LeCoffre.io - Base de données : Requêtes Prisma lentes, erreurs Prisma, erreurs connexion PostgreSQL
- LeCoffre.io - ClamAV Antivirus : Scans antivirus, malwares détectés
- LeCoffre.io - IdNot : Logs de connexion, synchronisation des offices
- LeCoffre.io - OVH/SMS : Logs SMS, codes 2FA
- LeCoffre.io - Stripe : Webhooks Stripe, abonnements
- LeCoffre.io - Mailchimp : Emails envoyés, erreurs d'envoi
- LeCoffre.io - Bitcoin Signet : Ancrages réussis/échoués, vérifications blockchain
- LeCoffre.io - Espace Tiers : Ajouts de tiers, documents consultés
- LeCoffre.io - Espace Client : Documents consultés, fichiers uploadés
- LeCoffre.io - Dossiers Invités : Partages de dossiers, accès notaires invités
- 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
{job="application-logs"}
Erreurs uniquement
{job="application-logs"} |~ "(ERROR|❌|error)"
Warnings
{job="application-logs"} |~ "(WARN|⚠️|warn)"
Logs ClamAV
{job="application-logs"} |= "[Antivirus]"
Malwares détectés
{job="application-logs"} |= "[Antivirus] Malware detected"
Logs de synchronisation
{job="sync-logs"}
Logs de déploiement
{job="deployment-logs"}
Métriques temporelles
Nombre d'erreurs par heure :
count_over_time({job="application-logs"} |= "ERROR" [1h])
Nombre de scans ClamAV par heure :
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 ClamAVERROR,❌,error: Erreurs généralesWARN,⚠️,warn: Warnings✅: Succès
Troubleshooting Monitoring
Problème "No Data" dans Grafana
1. Vérifier que les fichiers de logs existent :
# Sur le serveur distant
ls -la /home/debian/sites/<env>-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 :
# 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-<env>/positions.yaml
# Vérifier que les fichiers de logs existent
ls -la logs/
3. Vérifier la connexion Promtail → Loki :
# 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 :
# 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) :
- Sélectionner la datasource Loki
- Tester la requête :
{job="application-logs"} - 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 fichiersbackend-*.logoucron-*.log- Les conteneurs backend/cron démarrent mais n'écrivent pas de logs
Solutions :
- Vérifier que les scripts wrapper sont exécutables
- Vérifier les logs backend :
journalctl -u lecoffreio-backend@<domain> -n 100 - 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 denieddans les logs Promtail
Solutions :
- Vérifier les permissions des fichiers :
ls -la logs/ - Vérifier que Promtail a accès au répertoire des logs (configuration Promtail)
- Vérifier les permissions du répertoire logs/
Cause 3 : Promtail ne peut pas se connecter à Loki :
Symptômes :
- Erreurs
connection refuseddans les logs Promtail - Loki ne reçoit pas de logs
Solutions :
- Vérifier que Loki est démarré :
systemctl status lokiou selon déploiement - Vérifier que Promtail et Loki communiquent (même hôte ou URL configurée)
- 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 :
- Vérifier les labels disponibles :
curl http://localhost:3100/loki/api/v1/labels - Vérifier que les labels dans
promtail-config.ymlcorrespondent aux requêtes dans les dashboards - Vérifier que le label
jobest bien défini dans tous lesscrape_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 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
systemctl status loki promtail grafana-server
Vérifier les logs des services
# Loki
journalctl -u loki -n 100
# Promtail
journalctl -u promtail -n 100
# Grafana
journalctl -u grafana-server -n 100
Vérifier la connectivité Loki
curl -s http://127.0.0.1:3100/ready
Vérifier les fichiers de logs collectés
ls -la logs/
Vérifier les positions Promtail
cat /var/lib/lecoffre/promtail-<env>/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
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
backup-daily.sh: Script de sauvegarde quotidienne automatiquedisaster-recovery.sh: Script de récupération automatisée complètegandi-dns-api.sh: Script d'interaction avec l'API Gandi pour la bascule DNS
Configuration Initiale
1. Créer le fichier de configuration
cp .secrets/.env.backup.example .secrets/.env.backup
2. Configurer les variables
Éditez .secrets/.env.backup :
# 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 :
# 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 :
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 :
curl -H "Authorization: Apikey $GANDI_API_KEY" \
https://id.gandi.net/tokeninfo
Sauvegarde Quotidienne
Exécution Manuelle
./deploy/scripts/backup/backup-daily.sh
Configuration Cron (Automatique)
Sur le serveur prod, ajouter dans le crontab :
# 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'environnementnginx-prod.conf: Configuration Nginxcertbot-conf-prod/: Certificats SSL (live, archive, accounts, renewal)backup-metadata.json: Métadonnées (timestamp, Git commit, environnement)
Structure sur VM Gandi
/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
# 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 :
- Récupération de la sauvegarde depuis la VM Gandi
- Extraction de l'archive et vérification du contenu
- Préparation du serveur de récupération (vérification prérequis)
- Clone/update du repository Git sur le serveur de récupération
- Restauration des fichiers de configuration (.env, nginx, certificats)
- Upload du dump de base de données
- Bascule DNS via API Gandi (prod.lecoffreio.4nkweb.com → IP serveur de récupération)
- Attente de la propagation DNS (vérification toutes les 30 secondes)
- Restauration de la base de données sur le serveur de récupération
- Mise à jour des certificats SSL (renouvellement si nécessaire)
- Build et déploiement (build, démarrage services systemd)
- Vérification de la santé des services (backend, nginx)
- 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 :
# 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
# 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/ :
# 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 :
# 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 :
- Utiliser un serveur de test (ou VM temporaire)
- Exécuter
disaster-recovery.shavec une sauvegarde récente - Vérifier que tous les services fonctionnent
- 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 :
# Vérifier les logs
tail -100 logs/backup-daily-*.log
# Vérifier la connexion SSH au serveur prod
ssh -i ~/.ssh/id_ed25519 debian@<PROD_SERVER> "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 :
# 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@<domain> -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 :
# 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 :
# 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
# 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) :
# 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
# 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.backupdans Git - Limiter les permissions :
chmod 600 .secrets/.env.backup
Chiffrement (Optionnel)
Si vous souhaitez chiffrer les sauvegardes :
# 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
- Tests Réguliers : Tester la récupération trimestriellement
- Monitoring : Surveiller les logs de sauvegarde quotidienne
- Espace Disque : Surveiller l'espace disque sur la VM Gandi
- Documentation : Documenter toute modification du processus
- Validation : Valider manuellement après chaque récupération
Informations Validées
-
Infrastructure VM Gandi :
- Stockage : 250GB
- Machine cible : ssh debian@92.243.24.12
-
Stratégie de sauvegarde :
- Environnement : prod uniquement
- Conservation : 7 versions
-
API Gandi :
- Clé API : Fournie (stockée dans
.env.backup) - Permissions : Admin DNS
- Domaine : prod.lecoffreio.4nkweb.com
- Clé API : Fournie (stockée dans
-
Récupération :
- RTO (Recovery Time Objective) : 3 heures
- RPO (Recovery Point Objective) : 24 heures (sauvegarde quotidienne)
-
Sécurité :
- Gestion des clés : Fichiers
.env.backup - Chiffrement : Non requis (infrastructure privée)
- Gestion des clés : Fichiers
Références
Documentation
- Architecture : ARCHITECTURE.md
- Reset base de données :
docs/DATABASE_RESET_GUIDE.md - Scripts backend : 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>/env-full-<env>-for-bdd-injection.txt
Documentation externe
- Documentation Let's Encrypt : https://letsencrypt.org/docs/
- Documentation Nginx : https://nginx.org/en/docs/
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 <version> "<description>" ; 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)