Wiki
Sauvegarde et restauration
Comment QuoteNode gère les sauvegardes de base de données et de fichiers — archives chiffrées avec age, restauration pilotée par manifeste, kits de récupération et profils d'exécution.
Sauvegarde et restauration
QuoteNode intègre un système de sauvegarde qui protège vos données commerciales contre les pannes matérielles, les suppressions accidentelles et les incidents d’exploitation.
Ce qui est sauvegardé
Chaque sauvegarde crée une archive contenant :
- Dump de la base de données — un dump PostgreSQL complet au format personnalisé (
pg_dump --format=custom), incluant toutes les tables, séquences et contraintes. - Stockage de fichiers — tous les fichiers téléversés (images de produits, logos d’entreprise) et les PDF générés, archivés sous forme de
files.tar.gzavec des chemins relatifs. - Manifeste de sauvegarde — un fichier
backup-manifest.jsoncontenant la version source, le mode de chiffrement, le mode de charge utile de la base de données, les sommes de contrôle et les métadonnées de compatibilité de restauration. - Sommes de contrôle d’intégrité — un fichier
checksums.sha256contenant les empreintes SHA-256 de tous les composants de l’archive.
Les trois couches de chiffrement
Une sauvegarde met en jeu trois secrets/réglages indépendants. « Sauvegarde chiffrée » est ambigu — nommez toujours la couche :
- Identité privée AGE — déverrouille uniquement l’archive externe
.tar.age. Elle provient du Recovery Kit et sert lors de la restauration/vérification (RESTORE_AGE_IDENTITY_FILE). Elle ne contient pas et ne remplace pas laDB_ENCRYPTION_KEY. DB_ENCRYPTION_KEY— déchiffre les champsAPP_ENCRYPTEDde la base de données et les secrets opérationnels (MFA, SMTP, charges utiles des e-mails d’offre). Sauvegardez-la séparément de l’archive et ne la passez jamais en argument de ligne de commande.ENCRYPT_PII— la politique de stockage à l’exécution de la cible. Elle ne déchiffre pas d’archive ; la modifier ne remplace jamais la bonne clé ni le post-traitement de restauration.
Conservez vos secrets .env / de déploiement et le Recovery Kit dans des emplacements protégés séparés.
Chiffrement de l’archive
Les nouvelles sauvegardes chiffrées utilisent le chiffrement par destinataire age (AGE_RECIPIENT). C’est le seul modèle de chiffrement pris en charge pour les nouvelles archives.
- Le processus de sauvegarde n’utilise qu’un destinataire age public (
age1...) — aucune clé privée n’est nécessaire sur le serveur pour créer des sauvegardes. - Les archives chiffrées portent l’extension
.tar.age. - La somme de contrôle SHA-256 de l’archive chiffrée est stockée à côté de l’archive pour vérification côté opérateur.
- Le déchiffrement nécessite l’identité age privée correspondante, conservée exclusivement dans le kit de récupération de l’opérateur.
- L’identité age privée brute n’est jamais stockée dans la base de données, les journaux, les DTO ou les arguments de processus après la confirmation de la configuration.
Sauvegardes locales non chiffrées
Les sauvegardes locales non chiffrées (.tar) ne sont autorisées que lorsque toutes les conditions suivantes sont réunies :
BACKUP_ARCHIVE_ENCRYPTION_MODE=NONEBACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=true- La destination est le stockage local
BACKUP_DATABASE_PAYLOAD_MODE=APP_ENCRYPTED- L’administrateur a explicitement accepté le risque dans l’interface
Les archives non chiffrées sont bloquées pour le stockage distant et pour les charges utiles avec PII déchiffrées.
Configuration (.env). Le destinataire age est généré par le kit de récupération (Admin → Sécurité → Sauvegarde) et stocké dans l’instance — vous ne placez pas de clé dans le .env. Définissez uniquement les deux variables de mode :
BACKUP_ENABLED=true
# Second, dedicated switch — default off. Set true only on the backup-worker to run scheduled backups.
BACKUP_SCHEDULER_ENABLED=true
BACKUP_ARCHIVE_ENCRYPTION_MODE=AGE_RECIPIENT
BACKUP_DATABASE_PAYLOAD_MODE=APP_ENCRYPTED
# Alternative — encrypted archive + decrypted PII (cross-instance portability):
# BACKUP_DATABASE_PAYLOAD_MODE=PII_DECRYPTED
BACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=false
Pour désactiver le chiffrement de l’archive (local uniquement, non recommandé — les PII restent chiffrées dans la charge utile) :
BACKUP_ARCHIVE_ENCRYPTION_MODE=NONE
BACKUP_ALLOW_UNENCRYPTED_LOCAL_BACKUP=true
Avec
AGE_RECIPIENT, si aucun destinataire n’a encore été généré, la sauvegarde échoue bruyamment au lieu d’écrire une archive non protégée. La combinaisonNONE+PII_DECRYPTEDest rejetée.
Modes de charge utile de la base de données
| Mode | Description |
|---|---|
APP_ENCRYPTED |
Par défaut. Les champs PII restent chiffrés avec la clé applicative DB_ENCRYPTION_KEY. Restaurer sur la même clé (empreinte correspondante) ne demande aucune étape supplémentaire ; restaurer sur une clé différente exige la clé source d’origine (via PII_REKEY_OLD_KEY) pour un rechiffrement hors ligne, sinon la restauration est bloquée avant toute modification. |
PII_DECRYPTED |
Les champs PII sont déchiffrés dans une base de données temporaire avant l’archivage. Les empreintes des mots de passe utilisateurs restent inchangées. Nécessite le chiffrement d’archive AGE_RECIPIENT. Utile pour la portabilité entre instances. |
Lors de la restauration d’une sauvegarde PII_DECRYPTED dans une cible avec ENCRYPT_PII=true, le processus de restauration rechiffre automatiquement les PII avec la DB_ENCRYPTION_KEY de la cible avant le démarrage normal de l’application.
Kit de récupération
Pendant la configuration, l’administrateur génère (ou importe) un destinataire age pour les sauvegardes chiffrées. Le kit de récupération est un fichier ZIP contenant :
quotenode-age-identity.txt— l’identité age privée (retournée une seule fois)quotenode-age-recipient.txt— le destinataire public et l’empreintequotenode-backup-verify.sh— script de vérification local (Linux/macOS)quotenode-backup-verify.ps1— script de vérification local (Windows)README.md— commandes de vérification et de restauration
Critique : L’identité age privée n’est retournée qu’une seule fois lors de la génération du kit. En cas de perte, les archives chiffrées ne pourront pas être déchiffrées. Conservez le kit de récupération dans un emplacement hors ligne sécurisé.
L’administrateur doit confirmer que le kit a été enregistré et testé avant que l’assistant de configuration ne marque la sauvegarde comme prête pour la production.
Vérification locale des sauvegardes
Les sauvegardes téléchargées peuvent être vérifiées en dehors de l’application en cours d’exécution à l’aide des scripts du kit de récupération :
scripts/quotenode-backup-verify.sh \
--archive /path/backup.tar.age \
--identity /path/quotenode-age-identity.txt \
--expected-sha256 <sha256-from-ui-or-sidecar>
Le vérificateur :
- Compare la somme de contrôle SHA-256 de l’archive chiffrée à la valeur attendue ou au fichier annexe
.sha256. - Déchiffre avec
age -ddans un répertoire temporaire privé. - Valide les entrées tar (rejette les chemins absolus,
.., les liens symboliques et les fichiers de périphérique). - Vérifie que
backup-manifest.jsonexiste et possède une version prise en charge. - Exécute
sha256sum -c checksums.sha256. - Exécute
pg_restore --list db.dumplorsquepg_restoreest disponible. - Supprime par défaut les données temporaires déchiffrées (utilisez
--keep-decryptedpour les conserver).
Sauvegarde en ligne (par défaut)
Les sauvegardes en ligne s’exécutent pendant que l’application traite les requêtes. Il n’y a aucune interruption de service.
pg_dumpau format personnalisé crée un instantané cohérent sur le plan transactionnel sans verrouiller les tables ni bloquer les requêtes.- Le stockage de fichiers est archivé en parallèle — les fichiers téléversés et les PDF sont immuables après leur création, de sorte que l’archive est toujours cohérente.
- PostgreSQL n’a pas besoin de s’arrêter pour produire un dump de base de données cohérent.
Comment s’exécutent les sauvegardes : choisir une topologie
Il existe deux façons d’exécuter en continu les sauvegardes planifiées. Toutes deux produisent des archives identiques — elles ne diffèrent que par l’endroit où le job de sauvegarde s’exécute.
| Topologie | Quand l’utiliser | Conteneurs |
|---|---|---|
| Worker dédié (par défaut) | Production. Les sauvegardes s’exécutent dans un conteneur backup-worker distinct, de sorte qu’elles ne rivalisent jamais avec le trafic web pour la mémoire ou le CPU. |
backend web + backup-worker |
| In-process | Configurations personnalisées à un seul backend avec leur propre fichier Compose (les paquets de version ne l’utilisent pas). Le backend web exécute lui-même les sauvegardes — un conteneur de moins à gérer. | backend web uniquement |
Le job de sauvegarde lui-même est le même pipeline shell (pg_dump → archivage → chiffrement) dans les deux cas, exécuté en dehors du tas de la JVM, de sorte que son coût en mémoire est modeste.
Comment sélectionner une topologie
Deux variables d’environnement fonctionnent ensemble :
JOBS_MODEdétermine quel conteneur exécute réellement le job de sauvegarde planifié.BACKUP_RUNTIME_PROFILEest une étiquette enregistrée dans les journaux et manifestes de sauvegarde afin que vous puissiez voir, après coup, comment chaque sauvegarde a été produite.
| Topologie | Backend web | Worker de sauvegarde |
|---|---|---|
| Worker dédié (par défaut) | JOBS_MODE=web + BACKUP_RUNTIME_PROFILE=WORKER |
conteneur JOBS_MODE=backup-only |
| In-process | JOBS_MODE=all + BACKUP_RUNTIME_PROFILE=WEB_MAINTENANCE |
(aucun) |
Les paquets de version utilisent la topologie worker dédié pour toutes les installations (serveur, LAN, ordinateur portable, NAS et Coolify) : les deux fichiers Compose incluent un service
backup-workeret fixentJOBS_MODEpar service. Dans le paquet autonome, ce réglage Compose prime sur.env; le mode in-process (JOBS_MODE=all+BACKUP_RUNTIME_PROFILE=WEB_MAINTENANCE) exige donc un fichier Compose que vous maintenez vous-même.
Référence des profils d’exécution
BACKUP_RUNTIME_PROFILE accepte quatre valeurs. Les deux premières concernent les topologies continues ci-dessus ; les deux dernières concernent les sauvegardes ponctuelles pilotées par l’opérateur.
| Profil | Description |
|---|---|
WORKER |
Par défaut. Un conteneur backup-worker permanent exécute les sauvegardes planifiées via cron. |
WEB_MAINTENANCE |
Le backend web exécute directement les sauvegardes planifiées. Aucun conteneur worker supplémentaire n’est nécessaire. |
ONE_SHOT |
Un cron externe ou un opérateur exécute operator/backup-one-shot.sh puis se termine. Aucun worker permanent. |
OFFLINE_MAINTENANCE |
Un script automatisé annonce l’interruption, arrête frontend/backend/backup-worker, maintient PostgreSQL en fonctionnement, exécute la sauvegarde, redémarre les services et vérifie leur état. |
Sauvegarde ponctuelle (one-shot)
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
BACKUP_ARCHIVE_ENCRYPTION_MODE=AGE_RECIPIENT \
BACKUP_AGE_RECIPIENT=age1... \
./operator/backup-one-shot.sh
Maintenance hors ligne
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
BACKUP_OFFLINE_NOTICE_SECONDS=300 \
./operator/backup-offline-maintenance.sh
Le script de maintenance hors ligne :
- Annonce une maintenance planifiée (période de grâce configurable).
- Active éventuellement une page de maintenance statique pendant l’arrêt des services.
- Arrête le frontend, le backend et le backup-worker (maintient PostgreSQL en fonctionnement).
- Exécute une sauvegarde ponctuelle.
- Redémarre tous les services.
- Vérifie l’état du backend.
- Écrit un journal de maintenance JSONL au niveau de l’hôte.
Si le script échoue à un moment quelconque, un piège de sécurité redémarre automatiquement les services.
Utilisez --dry-run pour prévisualiser le plan sans l’exécuter :
./operator/backup-offline-maintenance.sh --dry-run
Planification
- Planification par défaut : tous les jours à 2h00 (
0 0 2 * * *, configurable viaBACKUP_CRON) - Activation (deux commutateurs) : les sauvegardes planifiées ne s’exécutent que si à la fois
BACKUP_ENABLED=trueetBACKUP_SCHEDULER_ENABLED=truesont définis.BACKUP_SCHEDULER_ENABLEDest un coupe-circuit dédié, désactivé par défaut, de sorte qu’activer les sauvegardes ne déclenche jamais une première exécution planifiée surprise. Ne l’activez que sur le backup-worker (profil d’exécutionWORKER/WEB_MAINTENANCE), jamais sur le niveau web. - Déclenchement manuel : les administrateurs peuvent déclencher une sauvegarde immédiate depuis le panneau d’administration ou via l’API (
POST /api/v1/admin/backup/trigger). Le déclencheur répond immédiatement (HTTP 202) tandis que la sauvegarde s’exécute de manière asynchrone. - Protection contre la concurrence : un verrou stocké en base de données garantit qu’une seule sauvegarde s’exécute à la fois, sur l’ensemble des workers et des déclenchements manuels.
Pour les profils ONE_SHOT et OFFLINE_MAINTENANCE, le planificateur interne est désactivé — les sauvegardes sont gérées en externe.
Options de stockage
Stockage local (par défaut)
Les sauvegardes sont stockées dans BACKUP_LOCAL_DIR (par défaut : /app/data/backups), mappé sur un volume Docker.
En production, les sauvegardes locales doivent être complétées par des copies distantes.
Stockage distant via rclone
Si BACKUP_RCLONE_REMOTE est configuré, les sauvegardes sont automatiquement téléversées vers une destination distante après leur création locale. rclone prend en charge plus de 70 fournisseurs de stockage cloud, dont les fournisseurs compatibles S3, Google Cloud Storage, Azure Blob, SFTP et WebDAV.
Téléchargement des sauvegardes
Le téléchargement des archives de sauvegarde nécessite une autorisation renforcée (step-up) :
- Accédez à Paramètres > Sauvegarde.
- Cliquez sur Télécharger sur l’entrée de sauvegarde.
- Saisissez votre mot de passe actuel (et le code TOTP si la MFA est activée).
- Le système émet une autorisation de téléchargement à usage unique et de courte durée (par défaut : 120 secondes).
- L’archive se télécharge automatiquement.
Le jeton d’autorisation n’est stocké que sous forme d’empreinte SHA-256. La création de l’autorisation et le téléchargement sont audités et les autres administrateurs sont notifiés.
Remarque : un téléchargement direct sans autorisation renvoie 403. Les sauvegardes sur stockage distant ne peuvent pas être téléchargées via le panneau d’administration.
Métadonnées et piste d’audit
Chaque sauvegarde est suivie dans la table backup_logs avec :
- Statut (RUNNING, SUCCESS, FAILED)
- Initiée par (SCHEDULER ou ADMIN)
- Heure de début/de fin
- Taille (octets) et somme de contrôle SHA-256
- Destination (chemin local ou URL distante)
- Version du manifeste et version de l’application source
- Mode de chiffrement de l’archive et empreinte
- Mode de charge utile de la base de données
- Profil d’exécution
- Statut de vérification (NOT_RUN, PASSED, FAILED, SKIPPED_TIMEOUT)
- Statut du test de restauration et statut de compatibilité de restauration
Restauration
Utilisation de operator/restore.sh
Le script de restauration canonique gère l’intégralité du cycle de vie :
COMPOSE_PROJECT_NAME=quotenode COMPOSE_FILE_PATH=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
DB_USERNAME="$(grep '^DB_USERNAME=' .env | cut -d= -f2-)" \
DB_NAME="$(grep '^DB_NAME=' .env | cut -d= -f2-)" \
DB_PASSWORD="$(grep '^DB_PASSWORD=' .env | cut -d= -f2-)" \
RESTORE_JOURNAL_DIR=$PWD/restore-journal \
RESTORE_AGE_IDENTITY_FILE=/path/to/quotenode-age-identity.txt \
[email protected] \
RESTORE_ADMIN_PASSWORD_FILE=/path/to/password \
./operator/restore.sh /path/to/backup.tar.age
Le script :
- Extrait et valide l’archive (manifeste, sommes de contrôle, sécurité des entrées tar).
- Effectue des contrôles préalables (capacité disque, version de PostgreSQL, connectivité à la base de données).
- Crée une sauvegarde de sécurité de la cible avant toute opération destructrice.
- Écrit un journal de restauration au niveau de l’hôte (JSONL, qui survit au remplacement de la base de données).
- Restaure la base de données.
- Prépare les fichiers dans un répertoire temporaire et les met en place par échange.
- Préserve l’identité de la cible (ID d’instance, métadonnées de chiffrement des sauvegardes, état de la licence).
- Efface les sessions, les liens publics d’offres et les jetons de notification.
- Réinitialise ou force la modification de l’accès administrateur.
- Rechiffre les PII si la sauvegarde est
PII_DECRYPTEDet que la cible aENCRYPT_PII=true.
Restauration entre instances
Lors de la restauration d’une sauvegarde provenant d’une autre installation, le mode par défaut est PRESERVE_TARGET_IDENTITY :
- L’ID d’instance cible, le destinataire age des sauvegardes, les métadonnées du kit de récupération et l’état de la licence sont préservés.
- Les sessions, les liens publics d’offres et les jetons de notification sont effacés.
- Le mot de passe administrateur est réinitialisé/sa modification est forcée.
- Les données métier sont entièrement remplacées (pas de fusion).
Compatibilité de restauration
Le contrôle préalable de restauration valide :
- Sauvegarde plus ancienne vers une application plus récente : autorisé (compatible).
- Sauvegarde plus récente vers une application plus ancienne : bloqué.
- Manifeste manquant : bloqué.
- Empreinte de clé de chiffrement incorrecte pour une charge utile
APP_ENCRYPTED: bloqué avant tout travail destructeur. PII_DECRYPTEDsans chiffrement d’archive : bloqué.
Décisions de récupération et actions sûres
Les décisions de la politique de restauration proviennent d’un seul moteur et renvoient des reason codes stables ; un résultat bloqué ne modifie rien.
- APP_ENCRYPTED vers une clé différente, sans clé source →
SOURCE_DB_ENCRYPTION_KEY_REQUIRED. Fournissez la clé d’origine viaPII_REKEY_OLD_KEY(variable d’environnement, jamais en argv) pour effectuer le rechiffrement. - Mauvaise clé source →
SOURCE_DB_ENCRYPTION_KEY_MISMATCH. Fournissez la bonne clé d’origine ; ne générez pas de clé de remplacement. - Cible PII en clair, non confirmée →
PLAINTEXT_PII_TARGET_NOT_ACKNOWLEDGED. DéfinissezRESTORE_ACKNOWLEDGE_PLAINTEXT_PII=trueuniquement si les PII en clair au repos sont voulues. - Aucune clé source vérifiée (PII_DECRYPTED uniquement) → les secrets opérationnels ne peuvent qu’être RÉINITIALISÉS. Définissez
RESTORE_ACKNOWLEDGE_OPERATIONAL_SECRET_RESET=truepour l’accepter. - Mauvaise identité AGE / échec d’intégrité → l’archive n’est pas ouverte et rien n’est modifié.
Conséquences de la réinitialisation des secrets opérationnels (si acceptée) : les enregistrements MFA sont réinitialisés et les utilisateurs doivent se réinscrire ; SMTP est effacé et l’e-mail sortant reste désactivé jusqu’à reconfiguration ; les charges utiles d’offer-email irrécupérables sont nettoyées et ne peuvent pas être renvoyées. FEATURE_2FA_ENABLED=false n’est qu’un break-glass d’urgence temporaire, jamais un réglage normal.
Sémantique du résultat de restauration :
- Succès — BD + fichiers restaurés, post-traitement crypto effectué, et seulement ensuite l’application peut servir le trafic.
- Refus avant mutation — une politique bloquée ou un preflight échoué laisse la cible inchangée.
- Rollback réussi — un échec après mutation restaure la BD + les fichiers ensemble depuis la sauvegarde de sécurité de la cible.
- Rollback échoué — l’application est délibérément laissée ARRÊTÉE avec tous les artefacts de récupération conservés ; restaurez depuis l’archive de sécurité.
À ne pas faire : générer une DB_ENCRYPTION_KEY de remplacement aléatoire ; passer un secret en argument de ligne de commande ; ni démarrer l’application web avant la fin du post-traitement crypto.
Garantie d’accès administrateur
La restauration garantit l’accès administrateur via l’une des options suivantes :
RESTORE_ADMIN_PASSWORD_FILE— mot de passe fourni par l’opérateur (défini avecforcePasswordChange=true)RESTORE_ADMIN_PASSWORD— pour un usage local/de test uniquement- Jeton de réinitialisation à usage unique généré automatiquement — affiché dans la console et dans le journal au niveau de l’hôte
Exécution à blanc (dry run)
RESTORE_DRY_RUN=true ./operator/restore.sh /path/to/backup.tar.age
Valide l’archive, vérifie les sommes de contrôle et le manifeste, et signale le plan de restauration sans rien modifier.
Reprise après sinistre — reconstruction à partir de zéro
Votre serveur a disparu. Vous disposez d’une archive de sauvegarde (.tar.age ou .tar) et d’un nouveau serveur avec Docker. Voici comment effectuer la restauration.
Étape 1 — Préparer le nouveau serveur
mkdir quotenode && cd quotenode
Configurez docker-compose.yml et .env comme décrit dans le guide d’installation.
Critique pour les sauvegardes APP_ENCRYPTED : le plus simple est de restaurer avec la même
DB_ENCRYPTION_KEY. Restaurer sur une clé différente fonctionne toujours si vous fournissez la clé d’origine viaPII_REKEY_OLD_KEYpour un rechiffrement. Sans la clé d’origine, les PIIAPP_ENCRYPTEDne sont pas récupérables (seule une archivePII_DECRYPTEDl’est, et ses secrets opérationnels doivent alors être réinitialisés) — ne générez jamais une clé de remplacement aléatoire.
Critique pour les archives chiffrées : vous avez besoin du fichier d’identité privée du kit de récupération (
quotenode-age-identity.txt) pour déchiffrer l’archive.
Étape 2 — Copier la sauvegarde et le script de restauration
scp backup.tar.age user@new-server:~/quotenode/
# operator/restore.sh comes with the release package (the release that created the backup, or a later one)
curl -fsSLO https://quotenode.dev/releases/v0.9.8-alpha/quotenode-deploy-v0.9.8-alpha.tar.gz
tar -xzf quotenode-deploy-v0.9.8-alpha.tar.gz --strip-components=1
Étape 3 — Exécuter la restauration
# Only a successful restore starts the remaining services (the restore itself starts PostgreSQL, the backend and
# the frontend). On failure nothing else starts and the restore's exit status is kept: read its message.
# Default installations keep PII unencrypted at rest (ENCRYPT_PII=false); a restore into such a target requires the
# explicit RESTORE_ACKNOWLEDGE_PLAINTEXT_PII acknowledgement below, for this command only. A target with
# ENCRYPT_PII=true in .env does not use it.
export COMPOSE_PROJECT_NAME=quotenode
COMPOSE_FILE_PATH=$PWD/docker-compose.yml COMPOSE_ENV_FILE=$PWD/.env \
DB_USERNAME="$(grep '^DB_USERNAME=' .env | cut -d= -f2-)" \
DB_NAME="$(grep '^DB_NAME=' .env | cut -d= -f2-)" \
DB_PASSWORD="$(grep '^DB_PASSWORD=' .env | cut -d= -f2-)" \
RESTORE_JOURNAL_DIR=$PWD/restore-journal \
RESTORE_AGE_IDENTITY_FILE=./quotenode-age-identity.txt \
[email protected] \
RESTORE_ADMIN_PASSWORD_FILE=./admin-password \
RESTORE_ACKNOWLEDGE_PLAINTEXT_PII=true \
./operator/restore.sh --fresh-install backup.tar.age \
&& docker compose up -d
Si la restauration signale un échec, ne démarrez pas QuoteNode à la main : une installation vide ou incomplètement restaurée démarrerait. Lisez le message, corrigez la cause (par exemple le fichier d’identité ou DB_ENCRYPTION_KEY) et relancez le bloc. Si la restauration indique avoir laissé l’application arrêtée en conservant les artefacts de récupération, suivez Décisions de récupération et actions sûres ci-dessus.
Étape 4 — Vérifier
Ouvrez votre domaine et connectez-vous. Tous les clients, offres, produits et paramètres devraient être exactement tels qu’ils étaient au moment de la sauvegarde.
Reprise après sinistre testée
Le parcours complet sauvegarde → restauration isolée est testé de bout en bout comme un exercice automatisé de reprise après sinistre (scénarios A–G) : restauration avec la même clé, rechiffrement vers une clé différente, confirmation des PII en clair, réinitialisation des secrets opérationnels, refus en cas d’identité incorrecte et rollback après restauration. Il s’exécute sur un vrai PostgreSQL dans un environnement jetable et vérifie les garanties de rollback et de clés décrites ci-dessus.
Rétention des sauvegardes
- Local : les
BACKUP_RETENTION_DAILY(par défaut : 7) sauvegardes réussies les plus récentes sont conservées. - Distant : configurez des politiques de cycle de vie chez votre fournisseur de stockage.
- Les sauvegardes avec PII déchiffrées devraient avoir une rétention plus stricte en raison de leur nature sensible.
Délai d’expiration des sauvegardes
Chaque sauvegarde a un délai d’expiration configurable (par défaut : 30 minutes via BACKUP_TIMEOUT_MINUTES). En cas de dépassement, la sauvegarde est interrompue et enregistrée comme FAILED.
Stratégie recommandée
- Activez les sauvegardes automatiques quotidiennes avec le chiffrement
AGE_RECIPIENTet le stockage distant. - Générez un kit de récupération lors de la configuration et conservez-le dans un emplacement hors ligne sécurisé.
- Vérifiez votre kit de récupération sur une sauvegarde réelle à l’aide des scripts de vérification inclus.
- Testez régulièrement les procédures de restauration — une sauvegarde qui n’a jamais été testée n’est pas une sauvegarde.
- Téléchargez une sauvegarde au moins une fois par mois vers un emplacement hors ligne (nécessite une autorisation renforcée).
- Surveillez l’état des sauvegardes dans le panneau d’administration — des avertissements apparaissent pour les sauvegardes obsolètes, échouées ou non chiffrées.
- Conservez au moins 7 jours d’historique de sauvegarde (la valeur par défaut).