# Memento — Guide Production : Monitoring, Backups & Résilience ## Architecture de production ``` ┌─────────────────────────────────────────────────────────┐ │ Serveur 192.168.1.190 (Proxmox) │ │ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ memento-note │ │ memento- │ │ memento- │ │ │ │ :3000 │ │ postgres │ │ redis │ │ │ │ (Next.js) │ │ :5433 │ │ :6379 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Stack Monitoring │ │ │ │ Prometheus:9090 / Grafana:3001 / Alertmanager │ │ │ │ node-exporter / postgres-exporter / redis-exp. │ │ │ │ cadvisor │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ Backups │ │ │ │ /opt/memento/backups/snapshots/ (pg_dump 6h) │ │ │ │ /opt/memento/backups/wal/ (WAL continu) │ │ │ │ Serveur externe (rsync journalier)│ │ └──────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────┘ │ │ │ Cloudflare │ rsync chiffré ▼ ▼ note.parsanet.org Serveur hors-site ``` --- ## 1. Protection des données ### 1.1 Niveaux de sauvegarde | Niveau | Méthode | Fréquence | RPO | Rétention | |--------|---------|-----------|-----|-----------| | 1 | WAL archiving (PITR) | Continu | ~1 seconde | 30 jours WAL | | 2 | pg_dump --format=custom | Toutes les 6h | 6h max | 7 jours + 4 snapshots hebdo | | 3 | rsync chiffré hors-site | Journalier 03h00 | 24h max | Même rétention que niveau 2 | | 4 | Pre-migration dump | Avant chaque deploy | Déploiement | 10 derniers | **RPO** (Recovery Point Objective) : quantité maximale de données qu'on peut perdre. **RTO** (Recovery Time Objective) : temps pour retrouver un service fonctionnel. ### 1.2 Scénarios de reprise | Scénario | RPO | RTO | Procédure | |----------|-----|-----|-----------| | Crash container app | 0 | ~30s | Docker restart automatique | | Crash process PostgreSQL | 0-5s | ~1min | Autorestart + WAL replay | | Corruption DB partielle | 0-6h | ~5min | `restore.sh snapshot` | | Corruption DB totale | 0-24h | ~15min | `restore.sh snapshot` + backup externe | | Serveur physique perdu | 0-24h | ~2h | Restore from backup externe | | Erreur humaine (DROP) | 0-6h | ~5min | `restore.sh pitr "YYYY-MM-DD HH:MM:SS"` | ### 1.3 Installation des sauvegardes ```bash # Sur le serveur 192.168.1.190 cd /opt/memento git pull # 1. Configurer les variables dans .env.docker # Ajouter : # TELEGRAM_BOT_TOKEN=your_bot_token # TELEGRAM_CHAT_ID=your_chat_id # BACKUP_REMOTE_HOST=user@backup-server (optionnel, pour hors-site) # 2. Activer le WAL archiving bash scripts/backup/setup-wal.sh # 3. Tester un snapshot manuel bash scripts/backup/backup.sh # 4. Vérifier le snapshot bash scripts/backup/verify-backups.sh # 5. Installer les crons bash scripts/backup/install-crontab.sh crontab /opt/memento/backups/crontab # 6. Vérifier les crons crontab -l ``` ### 1.4 Crons installés ``` # Snapshots toutes les 6h (00h00, 06h00, 12h00, 18h00) 0 */6 * * * /opt/memento/scripts/backup/backup.sh # Vérification 30min après chaque snapshot 30 */6 * * * /opt/memento/scripts/backup/verify-backups.sh # Synchronisation hors-site quotidienne à 03h00 0 3 * * * /opt/memento/scripts/backup/offsite-sync.sh ``` ### 1.5 Restauration ```bash # Restaurer le dernier snapshot (automatique) bash scripts/backup/restore.sh snapshot # Restaurer un snapshot spécifique bash scripts/backup/restore.sh snapshot /opt/memento/backups/snapshots/memento-20260517-120000.sql.gz # Point-in-time recovery (PITR) bash scripts/backup/restore.sh pitr "2026-05-17 14:30:00" ``` Le script `restore.sh` : 1. Dump la DB actuelle (safety net) 2. Stoppe l'app 3. Restore la DB 4. Vérifie le count de notes (abort si 0) 5. Redémarre l'app 6. Health check (180s timeout) 7. Log le résultat ### 1.6 Script de vérification `verify-backups.sh` vérifie toutes les 6h : - ✅ Un snapshot récent existe (< 8h) - ✅ Taille du snapshot > 1MB - ✅ Intégrité gzip du snapshot - ✅ DB contient des notes (count > 0) - ✅ App répond (HTTP < 500) - ✅ Espace disque < 85% Si un check échoue → **alerte Telegram immédiate**. --- ## 2. Monitoring ### 2.1 Installation ```bash # Sur le serveur 192.168.1.190 cd /opt/memento/monitoring # Configurer le mot de passe Grafana # Dans .env.docker, ajouter : # GRAFANA_ADMIN_PASSWORD=your_secure_password # Lancer la stack docker compose -f docker-compose.monitoring.yml up -d # Vérifier que tout est up docker compose -f docker-compose.monitoring.yml ps ``` ### 2.2 Accès | Service | URL | Identifiants | |---------|-----|-------------| | Grafana | http://192.168.1.190:3001 | admin / (mot de passe configuré) | | Prometheus | http://192.168.1.190:9090 | Aucun | | Alertmanager | http://192.168.1.190:9093 | Aucun | | cAdvisor | http://192.168.1.190:8080 | Aucun | ### 2.3 Exporters | Exporter | Port | Ce qu'il monitor | |----------|------|-----------------| | node-exporter | 9100 | CPU, RAM, disque, réseau du serveur | | postgres-exporter | 9187 | Connexions, requêtes, locks, taille DB | | redis-exporter | 9121 | Hit rate, mémoire, clés, TTL | | cadvisor | 8080 | CPU/RAM par conteneur Docker | ### 2.4 Alertes configurées | Alerte | Condition | Sévérité | |--------|-----------|----------| | MementoAppDown | App injoignable > 2min | Critical | | PostgresDown | PostgreSQL down > 1min | Critical | | RedisDown | Redis down > 1min | Critical | | DiskSpaceLow | Disque < 15% libre > 5min | Warning | | HighMemoryUsage | RAM > 90% > 5min | Warning | | PostgresConnectionsHigh | > 80 connexions > 5min | Warning | | PostgresSlowQueries | Requête moyenne > 5s | Warning | | HighErrorRate | Erreurs 5xx > 5% > 3min | Warning | | ContainerRestarted | Restart dans la dernière heure | Warning | ### 2.5 Configuration Grafana 1. Accéder à http://192.168.1.190:3001 2. Ajouter la datasource Prometheus : `http://prometheus:9090` 3. Importer les dashboards (IDs Grafana) : - **1860** — Node Exporter Full (serveur) - **9628** — PostgreSQL Database (DB) - **763** — Redis Dashboard (cache) - **193** — Docker Monitoring (conteneurs) ### 2.6 Health API ``` GET https://note.parsanet.org/api/admin/health ``` Retourne : ```json { "status": "healthy", "uptime": 86400, "version": "0.2.0", "components": { "database": { "status": "healthy", "latency": "12ms", "notes": 107 }, "redis": { "status": "healthy", "latency": "2ms", "keys": 847 }, "ai": { "status": "configured", "embedding": {"provider": "openrouter"} }, "storage": { "status": "healthy", "usagePercent": "23%" } } } ``` Utilisable par Prometheus, Grafana, ou tout outil de monitoring externe. --- ## 3. Déploiement ### 3.1 Pipeline CI/CD ``` Push → Gitea Actions CI → Lint + Test + Build ↓ (si succès) Deploy.yaml ↓ Dump DB (vérif > 1MB) ↓ Git pull + Docker build ↓ Health check (180s) ↓ échec Rollback automatique ↓ succès Notification Telegram ``` ### 3.2 Variables à configurer dans Gitea **Secrets :** - `SSH_PRIVATE_KEY` — clé SSH pour le serveur - `POSTGRES_PASSWORD` - `NEXTAUTH_SECRET` - `TELEGRAM_BOT_TOKEN` - `TELEGRAM_CHAT_ID` - `CUSTOM_OPENAI_API_KEY` **Variables :** - `APP_URL` — https://note.parsanet.org - `ADMIN_EMAIL` - `POSTGRES_USER`, `POSTGRES_DB`, `POSTGRES_PORT` - Toutes les variables AI provider ### 3.3 Rollback Le CI tag l'image Docker actuelle en `:rollback` avant chaque deploy. Si le health check échoue → restore automatique de l'image `:rollback`. En cas de problème DB : ```bash bash scripts/backup/restore.sh snapshot ``` --- ## 4. Checklist production ### Premier setup (à faire une seule fois) - [ ] `bash scripts/backup/setup-wal.sh` — activer WAL archiving - [ ] `bash scripts/backup/backup.sh` — tester le premier snapshot - [ ] `bash scripts/backup/verify-backups.sh` — vérifier le setup complet - [ ] `crontab /opt/memento/backups/crontab` — installer les crons - [ ] Configurer `TELEGRAM_BOT_TOKEN` + `TELEGRAM_CHAT_ID` dans `.env.docker` - [ ] `cd monitoring && docker compose -f docker-compose.monitoring.yml up -d` - [ ] Configurer Grafana (datasource + dashboards) - [ ] Configurer `BACKUP_REMOTE_HOST` pour le backup hors-site ### Vérification quotidienne (automatique) - [ ] Snapshots créés toutes les 6h ✓ (cron) - [ ] Vérification automatique ✓ (cron) - [ ] Sync hors-site journalier ✓ (cron) - [ ] Alertes Telegram si problème ✓ (Alertmanager) ### Vérification hebdomadaire (manuelle) - [ ] Ouvrir Grafana, vérifier les dashboards - [ ] Tester un restore sur une DB temporaire - [ ] Vérifier l'espace disque et la rotation des backups - [ ] Vérifier que les WAL ne grossissent pas trop --- ## 5. Sécurité ### 5.1 PostgreSQL - WAL archiving activé (PITR possible) - `archive_command` stocke les WAL dans `/var/lib/postgresql/backups/wal/` - Pas de connexion TRUST — md5/scram-sha-256 uniquement - Container non exposé sur internet (port 5433 interne uniquement) ### 5.2 Backups - Snapshots chiffrés si le filesystem est chiffré (recommandé LUKS) - rsync hors-site via SSH (chiffré en transit) - Permissions fichiers : 600 sur les snapshots - Les scripts vérifient l'intégrité avant de trust un backup ### 5.3 App - `DATABASE_URL` jamais exposé côté client - Secrets dans Gitea (encrypted at rest) - `.env.docker` en permission 600 sur le serveur - Rate limiting à configurer (P3) --- ## 6. Scripts de référence | Script | Usage | Fréquence | |--------|-------|-----------| | `scripts/backup/setup-wal.sh` | Activer WAL archiving | Once | | `scripts/backup/backup.sh` | Créer un snapshot | 6h (cron) | | `scripts/backup/verify-backups.sh` | Vérifier les backups | 6h (cron) | | `scripts/backup/restore.sh` | Restaurer la DB | Manuel (urgence) | | `scripts/backup/offsite-sync.sh` | Sync hors-site | 24h (cron) | | `scripts/backup/install-crontab.sh` | Installer les crons | Once | | `dump-db.sh` | Dump rapide (dev) | Manuel | | `scripts/deploy-prod.sh` | Deploy manuel | Manuel | | `scripts/migrate-docker.sh` | Migrer la DB | Après deploy |