agenthub/docs/RUNBOOK-restore.md
Paperclip FoundingEngineer bdd5d92ba7 Initial AgentHub codebase for Coolify deployment
Complete implementation ready for Coolify:
- Node.js 22 + Fastify + socket.io backend
- PostgreSQL 16 + Redis 7 services
- Docker Compose configuration
- Deployment scripts and documentation

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-05-01 21:25:57 +00:00

11 KiB
Raw Blame History

AgentHub Backup & Restore Runbook

Version: 1.0
Date: 2026-04-30
Maintainer: FoundingEngineer
Related ADR: ADR-0004 Déploiement


Table of Contents

  1. Backup Strategy
  2. Automated Backups
  3. Manual Backup
  4. Restore Procedure
  5. Disaster Recovery
  6. Weekly Encrypted Backups
  7. Troubleshooting

Backup Strategy

AgentHub utilise une stratégie de backup à deux niveaux :

  1. Backups locaux journaliers : pg_dump à 03:00 UTC, rétention 14 jours sur /opt/agenthub/backups
  2. Backups distants hebdomadaires : copie chiffrée GPG vers Scaleway Object Storage Paris, rétention 8 semaines

RPO (Recovery Point Objective) : 24 heures
RTO (Recovery Time Objective) : < 30 minutes pour un restore standard


Automated Backups

Les backups sont orchestrés par Ofelia (scheduler Docker) qui exécute le container backup quotidiennement.

Vérifier le statut des backups

# Lister les backups locaux
ls -lh /opt/agenthub/backups/

# Vérifier les logs Ofelia
docker compose -f compose.lan.yml logs ofelia

# Vérifier les logs du dernier backup
docker compose -f compose.lan.yml logs backup | tail -50

Configuration du backup automatique

Le service backup est configuré dans compose.lan.yml et compose.coolify.yml :

  • Schedule : 0 0 3 * * * (03:00 UTC tous les jours)
  • Rétention locale : 14 jours (gérée automatiquement par le script)
  • Format : PostgreSQL custom format (-Fc), optimal pour restore sélectif
  • Destination : /opt/agenthub/backups/agenthub_YYYYMMDD_HHMMSS.dump

Manual Backup

Backup manuel immédiat

# Exécuter un backup manuel
docker compose -f compose.lan.yml run --rm backup

# Vérifier que le backup est créé
ls -lh /opt/agenthub/backups/ | tail -1

Backup one-shot hors Docker

# Depuis l'hôte (nécessite psql installé)
PGPASSWORD='<postgres-password>' pg_dump -Fc \
  -h localhost \
  -p 5432 \
  -U agenthub \
  -d agenthub \
  -f "/opt/agenthub/backups/manual_$(date -u +%Y%m%d_%H%M%S).dump"

Restore Procedure

Pré-requis

  • Fichier de backup disponible (.dump)
  • Accès au serveur Postgres cible
  • Variables d'environnement Postgres configurées (PGHOST, PGUSER, PGPASSWORD)

Restore standard (production down)

Cas d'usage : restaurer la base de production après corruption ou perte de données.

# 1. Arrêter l'application pour éviter les connexions actives
docker compose -f compose.lan.yml stop app

# 2. Lancer le restore (interactive confirmation)
docker compose -f compose.lan.yml run --rm \
  -e PGHOST=postgres \
  -e PGDATABASE=agenthub \
  -e PGUSER=agenthub \
  -e PGPASSWORD="${POSTGRES_PASSWORD}" \
  backup \
  /usr/local/bin/restore.sh /backups/agenthub_20260430_030000.dump

# 3. Vérifier l'intégrité après restore
docker compose -f compose.lan.yml run --rm postgres \
  psql -h postgres -U agenthub -d agenthub -c "SELECT COUNT(*) FROM agents;"

# 4. Redémarrer l'application
docker compose -f compose.lan.yml start app

Restore vers base éphémère (test)

Cas d'usage : valider un backup avant de l'utiliser en production.

# 1. Créer une base de test
docker compose -f compose.lan.yml exec postgres \
  psql -U agenthub -d postgres -c "CREATE DATABASE agenthub_test OWNER agenthub;"

# 2. Restore vers la base de test
docker compose -f compose.lan.yml run --rm \
  -e PGHOST=postgres \
  -e PGDATABASE=agenthub_test \
  -e PGUSER=agenthub \
  -e PGPASSWORD="${POSTGRES_PASSWORD}" \
  -e SKIP_CONFIRMATION=yes \
  backup \
  /usr/local/bin/restore.sh /backups/agenthub_20260430_030000.dump agenthub_test

# 3. Vérifier la restauration
docker compose -f compose.lan.yml exec postgres \
  psql -U agenthub -d agenthub_test -c "\dt"

# 4. Comparer le nombre de tables
PROD_TABLES=$(docker compose -f compose.lan.yml exec postgres \
  psql -U agenthub -d agenthub -t -c \
  "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public';")

TEST_TABLES=$(docker compose -f compose.lan.yml exec postgres \
  psql -U agenthub -d agenthub_test -t -c \
  "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='public';")

echo "Prod tables: ${PROD_TABLES}"
echo "Test tables: ${TEST_TABLES}"

# 5. Cleanup
docker compose -f compose.lan.yml exec postgres \
  psql -U agenthub -d postgres -c "DROP DATABASE agenthub_test;"

Disaster Recovery

Scénario 1 : Corruption de la base de production

Impact : Application down, données corrompues

  1. Arrêter l'application : docker compose -f compose.lan.yml stop app
  2. Identifier le dernier backup sain : ls -lht /opt/agenthub/backups/ | head -5
  3. Restaurer depuis ce backup (voir Restore standard)
  4. Redémarrer : docker compose -f compose.lan.yml start app
  5. Smoke test : curl -fsS http://<host>:3000/healthz

Temps estimé : 510 minutes


Scénario 2 : Perte totale du volume pgdata

Impact : Volume Docker perdu, base de données inexistante

  1. Recréer le volume : docker volume create <project>_pgdata
  2. Démarrer Postgres : docker compose -f compose.lan.yml up -d postgres
  3. Attendre que Postgres initialise : docker compose -f compose.lan.yml logs -f postgres
  4. Restaurer le dernier backup (voir Restore standard)
  5. Redémarrer l'application : docker compose -f compose.lan.yml up -d

Temps estimé : 1015 minutes


Scénario 3 : Perte totale du serveur

Impact : Serveur hôte down, backups locaux inaccessibles

  1. Provisionner un nouveau serveur (voir scripts/bootstrap.sh dans le repo)
  2. Télécharger le backup hebdomadaire chiffré depuis Scaleway Object Storage :
    aws s3 cp \
      "s3://${S3_BUCKET}/weekly/agenthub_<date>.dump.gpg" \
      /tmp/backup.dump.gpg \
      --endpoint-url "${S3_ENDPOINT}"
    
  3. Déchiffrer le backup :
    gpg --decrypt /tmp/backup.dump.gpg > /tmp/backup.dump
    
  4. Copier le backup dans le volume :
    mkdir -p /opt/agenthub/backups
    mv /tmp/backup.dump /opt/agenthub/backups/
    
  5. Lancer la stack : docker compose -f compose.lan.yml up -d
  6. Restaurer (voir Restore standard)

Temps estimé : 3060 minutes (selon taille du backup et bande passante)


Weekly Encrypted Backups

Les backups hebdomadaires (dimanche 03:00 UTC) sont chiffrés GPG et uploadés vers Scaleway Object Storage.

Vérifier les backups distants

# Lister les backups sur Scaleway
aws s3 ls "s3://${S3_BUCKET}/weekly/" --endpoint-url "${S3_ENDPOINT}"

Télécharger et déchiffrer un backup distant

# Télécharger
aws s3 cp \
  "s3://${S3_BUCKET}/weekly/agenthub_20260427_030000.dump.gpg" \
  /tmp/backup.dump.gpg \
  --endpoint-url "${S3_ENDPOINT}"

# Déchiffrer (nécessite la clé privée GPG correspondante)
gpg --decrypt /tmp/backup.dump.gpg > /tmp/backup.dump

# Restaurer
# (voir section Restore Procedure)

Configuration S3 et GPG

Les variables d'environnement suivantes doivent être configurées dans .env :

S3_ENDPOINT=https://s3.fr-par.scw.cloud
S3_BUCKET=agenthub-backups-paris
AWS_ACCESS_KEY_ID=<scaleway-access-key>
AWS_SECRET_ACCESS_KEY=<scaleway-secret-key>
GPG_RECIPIENT_KEY=<gpg-public-key-id>

Troubleshooting

Le backup automatique ne s'exécute pas

Symptômes : Aucun nouveau backup depuis > 24h

  1. Vérifier que le service Ofelia est up :
    docker compose -f compose.lan.yml ps ofelia
    
  2. Vérifier les logs Ofelia :
    docker compose -f compose.lan.yml logs ofelia | grep backup-daily
    
  3. Vérifier les labels du service backup dans compose.lan.yml :
    labels:
      ofelia.enabled: "true"
      ofelia.job-exec.backup-daily.schedule: "0 0 3 * * *"
      ofelia.job-exec.backup-daily.command: "/usr/local/bin/backup.sh"
    
  4. Relancer Ofelia :
    docker compose -f compose.lan.yml restart ofelia
    

Le restore échoue avec "permission denied"

Cause probable : Mauvais utilisateur Postgres ou base verrouillée

  1. Vérifier que l'application est arrêtée :
    docker compose -f compose.lan.yml stop app
    
  2. Tuer les connexions actives :
    docker compose -f compose.lan.yml exec postgres \
      psql -U postgres -d postgres -c \
      "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='agenthub';"
    
  3. Relancer le restore

Backup file is empty or missing

Cause probable : pg_dump a échoué (credentials, réseau, espace disque)

  1. Vérifier les logs du container backup :
    docker compose -f compose.lan.yml logs backup
    
  2. Vérifier l'espace disque sur l'hôte :
    df -h /opt/agenthub/backups
    
  3. Tester manuellement pg_dump :
    docker compose -f compose.lan.yml run --rm backup \
      pg_dump -h postgres -U agenthub -d agenthub --version
    

GPG encryption fails lors du backup hebdomadaire

Cause probable : GPG_RECIPIENT_KEY manquant ou invalide

  1. Vérifier que la clé GPG est importée dans le container :
    docker compose -f compose.lan.yml run --rm backup gpg --list-keys
    
  2. Importer la clé publique si manquante :
    docker compose -f compose.lan.yml run --rm backup \
      gpg --import /path/to/public-key.asc
    
  3. Vérifier la variable d'environnement GPG_RECIPIENT_KEY dans .env

Drill de restore (procédure mensuelle recommandée)

Objectif : Valider que les backups sont restaurables et complets.

# 1. Sélectionner un backup récent
BACKUP_FILE="/opt/agenthub/backups/$(ls -t /opt/agenthub/backups/ | head -1)"
echo "Testing backup: ${BACKUP_FILE}"

# 2. Restore vers base éphémère
# (voir section "Restore vers base éphémère (test)")

# 3. Vérifier le checksum du backup
sha256sum "${BACKUP_FILE}" > /tmp/backup-checksum.txt
cat /tmp/backup-checksum.txt

# 4. Comparer le nombre de tables
# (voir section "Restore vers base éphémère (test)")

# 5. Cleanup et documenter
# Enregistrer le résultat du drill dans un log de suivi

Fréquence recommandée : 1 fois par mois minimum


Contacts et Escalation

  • Responsable technique : FoundingEngineer
  • Documentation source : agenthub/docs/RUNBOOK-restore.md
  • Scripts : agenthub/scripts/{backup,restore}.sh
  • ADR associé : ADR-0004