**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
2362 lines
80 KiB
Markdown
2362 lines
80 KiB
Markdown
# 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.<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>/.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 `--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 <env>` (baseline + import full)
|
||
2. **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/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.<env>` mais dans `.secrets/<env>/env-full-<env>-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.<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=<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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
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
|
||
|
||
1. Le script `build-and-deploy.sh` vérifie que `.env.<env>` existe
|
||
2. Il source le fichier avec `source .env.<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/<ENV>/bdd.<ENV>`
|
||
➜ **Important** : relancer ensuite `npm run config:import-env -- --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 <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 :**
|
||
|
||
```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.<env>`
|
||
|
||
#### Phase 3 : Build distant
|
||
|
||
1. ✅ Backup base de données (pg_dump)
|
||
2. ✅ Build backend/frontend
|
||
3. ✅ Chargement variables `.env.<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-<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.
|
||
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@<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 :
|
||
|
||
```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-<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** :
|
||
|
||
```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-<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](./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/<env>/bdd.<env>` (`--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-<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 (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 <env>` (baseline + import full + scripts post-déploiement)
|
||
2. **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.
|
||
|
||
```bash
|
||
# 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`).
|
||
|
||
```bash
|
||
# 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**
|
||
|
||
```bash
|
||
# 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**
|
||
|
||
```bash
|
||
# Usage
|
||
bash deploy/scripts/cleanup-remote-disk-aggressive.sh <ENV>
|
||
```
|
||
|
||
**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 <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** :
|
||
|
||
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@<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
|
||
|
||
```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@<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
|
||
|
||
```bash
|
||
# 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
|
||
|
||
```bash
|
||
# 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
|
||
|
||
```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@<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
|
||
|
||
```bash
|
||
cp env.bitcoin.api.deploy.example .env.bitcoin.api.deploy
|
||
nano .env.bitcoin.api.deploy # Configurer serveur Bitcoin
|
||
```
|
||
|
||
**Variables requises** :
|
||
|
||
```bash
|
||
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
|
||
|
||
```bash
|
||
./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
|
||
|
||
```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) │ │
|
||
│ │ <IP_POSTGRESQL>:<PORT_POSTGRESQL> │ │
|
||
│ └─────────────────────────────────────────────────────┘ │
|
||
└─────────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 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@<domain> -f
|
||
|
||
# Health check backend
|
||
curl https://test-lecoffreio.4nkweb.com/health
|
||
```
|
||
|
||
### Logs après déploiement (depuis machine distante)
|
||
|
||
```bash
|
||
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
|
||
|
||
```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-<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é)** :
|
||
|
||
1. URL : `https://<DEPLOY_DOMAIN>/monitor/`
|
||
2. Authentification : Identifiants configurés dans `.env.<env>`
|
||
- User : `GRAFANA_ADMIN_USER`
|
||
- Password : `GRAFANA_ADMIN_PASSWORD`
|
||
|
||
**Via tunnel SSH (fallback)** :
|
||
|
||
```bash
|
||
ssh -L 3000:127.0.0.1:3000 debian@<DEPLOY_SSH_HOST>
|
||
```
|
||
|
||
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/<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** :
|
||
|
||
```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-<env>/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@<domain> -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-<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
|
||
|
||
```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@<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** :
|
||
|
||
```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@<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** :
|
||
|
||
```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>/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)
|