Sauvegardes et récupération

Sur cette page

Un point de récupération doit restaurer la base de données complète. Les sauvegardes JSON d’EmDash sont utiles pour l’inspection et les outils personnalisés, mais EmDash ne peut pas les restaurer. Utilisez une sauvegarde brute de la base de données ou la récupération à un instant donné avant une migration de base de données ou une opération destructive.

Sauvegardez les fichiers binaires des médias séparément. Si le site stocke des paramètres de plugin chiffrés, conservez la liste de rotation complète de EMDASH_ENCRYPTION_KEY dans une sauvegarde distincte du gestionnaire de secrets. Les sauvegardes et exports de la base de données ne contiennent ni ces fichiers ni ces clés.

Choisir une méthode de récupération

Utilisez la méthode correspondant à l’adaptateur de base de données configuré du site :

Base de donnéesPoint de récupération
Cloudflare D1Notez un signet Time Travel. Créez un dump SQL hors site lorsque la rétention requise dépasse celle de Time Travel ou lorsqu’une répétition de restauration est nécessaire.
SQLite ou libSQL localUtilisez la commande de sauvegarde en ligne de SQLite, puis exécutez un contrôle d’intégrité sur la copie.
PostgreSQLUtilisez la récupération à un instant donné du fournisseur ou créez une archive au format personnalisé avec pg_dump.
HyperdriveSauvegardez son origine PostgreSQL via une connexion directe à l’origine. Un binding Hyperdrive n’est pas une connexion de sauvegarde.
libSQL hébergé par TursoUtilisez la récupération à un instant donné de Turso, ou créez et répétez un dump SQL.
Autre fournisseur libSQL distantUtilisez la procédure d’export complet de la base de données ou de récupération à un instant donné du fournisseur, et testez-la sur une base de données isolée.

Conservez le point de récupération avec l’artefact d’application correspondant, la sauvegarde des médias et la version de la liste de clés. Avant une migration planifiée, notez la base de données et l’environnement exacts, arrêtez les écritures de l’application lorsque la procédure du fournisseur l’exige, et confirmez que le point de récupération reste disponible pendant la fenêtre de retour arrière prévue.

Sauvegarder et restaurer les objets multimédias

Les buckets R2 et compatibles S3 nécessitent une sauvegarde au niveau des objets en plus de la base de données. La commande AWS CLI suivante copie tous les objets, y compris les archives JSON d’EmDash sous backups/, vers un répertoire de sauvegarde local. Pour AWS S3, omettez --endpoint-url.

aws s3 sync s3://emdash-media ./emdash-media-backup \
  --endpoint-url https://<account-id>.r2.cloudflarestorage.com

Remplacez <account-id> par l’ID du compte Cloudflare. Utilisez des identifiants de bucket en lecture seule pour les tâches de sauvegarde courantes. Stockez la sauvegarde en dehors du compte de production ou du domaine de panne, et notez le point de récupération de la base de données créé au même moment.

Restaurez dans un bucket de récupération vide plutôt que d’écraser la production pendant qu’elle traite des requêtes :

aws s3 sync ./emdash-media-backup s3://emdash-media-recovery \
  --endpoint-url https://<account-id>.r2.cloudflarestorage.com

Donnez à la tâche de restauration un accès en écriture uniquement au bucket de récupération. Faites pointer un déploiement hors production vers la base de données et le bucket restaurés, ouvrez plusieurs URL de médias connues, puis téléversez et supprimez un fichier jetable. Ne modifiez le binding de production ou la configuration du bucket qu’une fois que la base de données et les médias ont réussi leurs vérifications ensemble.

Pour le stockage local, copiez le répertoire configuré par l’adaptateur de stockage local(). Arrêtez les écritures de médias pendant la copie, puis vérifiez des fichiers représentatifs de la copie.

Récupérer une base de données D1 avec Time Travel

Avant une migration, demandez à Time Travel le signet actuel de la base de données et notez la sortie complète avec le déploiement :

npx wrangler d1 time-travel info my-database

Les points de récupération Time Travel expirent. Cloudflare les conserve actuellement 7 jours avec l’offre Workers Free et 30 jours avec l’offre Workers Paid. Créez un dump D1 hors site lorsque la fenêtre de retour arrière doit durer plus longtemps.

Si une récupération est nécessaire, arrêtez les écritures sur le site et restaurez exactement le signet noté avant la migration :

npx wrangler d1 time-travel restore my-database \
  --bookmark="<pre-migration-bookmark>"

Remplacez <pre-migration-bookmark> par le signet noté. La commande écrase la base de données sur place et annule les requêtes en cours. Enregistrez le signet précédent affiché par la commande de restauration afin de pouvoir annuler la restauration elle-même.

Time Travel restaure le contenu, les utilisateurs, les paramètres, les données des plugins et les enregistrements de migration. Il ne restaure ni les objets multimédias R2 ni EMDASH_ENCRYPTION_KEY. Restaurez l’artefact d’application, les médias et les clés correspondants avant de rouvrir le trafic. Vérifiez la connexion, la lecture du contenu, le schéma, un paramètre de plugin chiffré et une écriture.

Consultez la documentation D1 Time Travel pour connaître la rétention, les prérequis et le comportement de restauration actuels.

Créer un dump D1 hors site

Pour un dump SQL de la base de données brute (y compris les tables d’utilisateurs et d’authentification), utilisez Wrangler. Un simple wrangler d1 export my-database --remote échoue avec D1 Export error: cannot export databases with Virtual Tables (fts5) dès qu’une collection a la recherche activée, car EmDash conserve son index de recherche dans des tables virtuelles FTS5. Exportez les autres tables par leur nom et laissez de côté l’index de recherche ; le site restauré le reconstruit.

Le dump est réparti en quatre fichiers afin que la restauration réussisse :

  • backup-schema.sql crée les tables.
  • backup-folders.sql contient les dossiers de médias. Les imports volumineux s’exécutent par parties ; sans cela, un média serait inséré avant le dossier auquel il appartient et échouerait au contrôle de clé étrangère.
  • backup-data.sql contient toutes les autres lignes.
  • backup-indexes.sql contient les index et les triggers, qu’un export par nom de table laisse de côté. Ils sont créés en dernier afin que les triggers ne se déclenchent pas pendant l’import des lignes.

Ces commandes nécessitent jq. Les commandes suivantes écrivent les quatre fichiers :

npx wrangler d1 execute my-database --remote --json \
  --command "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT GLOB '_emdash_fts_*' AND name NOT GLOB 'sqlite_*' AND name NOT GLOB '_cf_*' AND name != 'media_folders'" \
  | jq -r '.[0].results[] | "--table=" + .name' > backup-tables.txt

npx wrangler d1 export my-database --remote --no-data --output=backup-schema.sql \
  --table=media_folders $(cat backup-tables.txt)
npx wrangler d1 export my-database --remote --no-schema --output=backup-folders.sql \
  --table=media_folders
npx wrangler d1 export my-database --remote --no-schema --output=backup-data.sql \
  $(cat backup-tables.txt)

npx wrangler d1 execute my-database --remote --json \
  --command "SELECT sql FROM sqlite_master WHERE type IN ('index', 'trigger') AND sql IS NOT NULL AND name NOT GLOB '_emdash_fts_*' AND tbl_name NOT GLOB '_emdash_fts_*' AND tbl_name NOT GLOB '_cf_*'" \
  | jq -r '.[0].results[] | .sql + ";"' > backup-indexes.sql

Consultez la documentation d’import et d’export de D1 pour les options et les limites d’export de Wrangler.

Conservez les fichiers SQL avec la version d’application correspondante, la sauvegarde des médias créée au même moment et une copie stockée séparément de la liste de rotation de EMDASH_ENCRYPTION_KEY. Testez la récupération en important les fichiers dans une base de données D1 vide nouvellement provisionnée, en restaurant les clés d’exécution, en faisant pointer un binding hors production vers cette base de données et en vérifiant le site.

Importez les fichiers dans la base de données de récupération vide dans cet ordre :

npx wrangler d1 execute my-recovery-database --remote --file=backup-schema.sql
npx wrangler d1 execute my-recovery-database --remote --file=backup-folders.sql
npx wrangler d1 execute my-recovery-database --remote --file=backup-data.sql
npx wrangler d1 execute my-recovery-database --remote --file=backup-indexes.sql

La base de données restaurée n’a pas d’index de recherche. EmDash le reconstruit la première fois que l’API de recherche (/_emdash/api/search) est appelée sur le site restauré, par exemple par la palette de commandes de l’administration ou par un champ de recherche qui utilise l’API. D’ici là, les pages qui appellent search() directement ne renvoient aucun résultat. Pour le reconstruire immédiatement, demandez une fois /_emdash/api/search?q=a une fois le site en marche.

Sauvegarder SQLite et libSQL local

Pour une sauvegarde hors ligne, arrêtez tous les processus qui écrivent dans la base de données et copiez le fichier de base de données ainsi que les fichiers -wal et -shm situés à côté. Le fichier -wal peut contenir des modifications validées qui ne sont pas encore dans le fichier principal.

Pour une sauvegarde en ligne cohérente, utilisez la commande de sauvegarde de SQLite sur le chemin configuré par l’adaptateur de base de données :

sqlite3 emdash.db ".backup backup.db"

Vérifiez la base de données copiée. La commande doit afficher ok :

sqlite3 backup.db "PRAGMA integrity_check"

Ouvrez la copie avec la version d’application correspondante dans un environnement hors production et vérifiez la connexion, le contenu public, un paramètre de plugin chiffré, une modification et une lecture de média.

Pour récupérer, arrêtez tous les processus qui écrivent dans la base de données, conservez une copie de la base endommagée et de ses fichiers -wal et -shm, remplacez-la par la sauvegarde vérifiée, et restaurez l’artefact d’application, les médias et les clés correspondants avant de rouvrir le trafic.

Sauvegarder PostgreSQL et Hyperdrive

Utilisez la récupération à un instant donné ou la fonctionnalité d’instantanés du fournisseur PostgreSQL lorsqu’elle offre une restauration isolée pouvant être testée avant de modifier la production. Notez l’horodatage ou l’ID d’instantané exact et la durée de rétention.

Pour une sauvegarde portable, connectez-vous directement à l’origine PostgreSQL et créez une archive au format personnalisé :

pg_dump --format=custom --file=emdash.dump "$DATABASE_URL"

pg_dump crée une archive cohérente sur le plan transactionnel pendant que la base de données reste utilisée. Inspectez la table des matières de l’archive avant de vous y fier :

pg_restore --list emdash.dump > emdash.dump.list

Provisionnez une base de données de récupération vide. Connectez-vous avec le rôle d’application canonique d’EmDash et restaurez sans reporter la propriété de la source dans la base de données de récupération :

pg_restore --exit-on-error --no-owner \
  --dbname="$RECOVERY_DATABASE_URL" emdash.dump

Le rôle de RECOVERY_DATABASE_URL devient propriétaire des objets EmDash restaurés. Utilisez le même rôle stable que l’application récupérée utilisera. Faites pointer un déploiement hors production vers la base de données de récupération et vérifiez la connexion, la lecture du contenu, le schéma, un paramètre de plugin chiffré et une écriture.

Pour Hyperdrive, DATABASE_URL doit être la connexion directe à l’origine PostgreSQL désignée par migrationConnectionStringEnv ; le binding du Worker ne peut pas être transmis aux outils de sauvegarde PostgreSQL. Suivez la procédure de récupération du fournisseur de l’origine et conservez la configuration Hyperdrive avec l’artefact d’application.

Consultez la documentation de sauvegarde PostgreSQL pour la récupération gérée par le fournisseur, les grosses bases de données et l’archivage continu.

Sauvegarder libSQL hébergé par Turso

La récupération à un instant donné de Turso crée une base de données distincte à partir d’un horodatage antérieur. Notez un horodatage RFC 3339 juste avant la migration. Si une récupération est nécessaire, créez une base de données isolée à partir de ce point :

turso db create emdash-recovery \
  --from-db emdash-production \
  --timestamp <pre-migration-rfc3339-timestamp>

Remplacez <pre-migration-rfc3339-timestamp> par l’horodatage noté. Créez un jeton pour la base de données récupérée, faites-y pointer un déploiement hors production et vérifiez le site avant de modifier la connexion de production. Consultez la récupération à un instant donné de Turso pour connaître la rétention fournie par l’offre du site.

Pour une copie hors site, faites un dump de la base de données complète :

turso db shell emdash-production .dump > emdash.sql

Testez le dump en créant à partir de lui une base de données isolée :

turso db create emdash-recovery --from-dump ./emdash.sql

Pour un autre fournisseur libSQL distant, suivez sa procédure d’export complet de la base de données ou de récupération à un instant donné. N’appliquez pas de migration distante tant que cette procédure n’a pas produit un point de récupération et qu’une restauration isolée n’a pas été testée.

Utiliser les sauvegardes JSON pour l’inspection

Une sauvegarde JSON comprend :

  • Toutes les entrées de contenu, y compris les brouillons, les articles planifiés et les éléments de la corbeille
  • Les définitions de collections et de champs qui forment le modèle de contenu
  • Les définitions de taxonomies, les termes et les termes attribués à chaque entrée
  • Les menus et leurs éléments, les sections, les zones de widgets et les widgets, les enregistrements SEO, l’historique des révisions, les métadonnées des médias et l’historique des migrations de la base de données
  • Les paramètres du site tels que le titre, le slogan, l’URL, la locale, le logo, les préférences d’affichage, les profils sociaux et les valeurs SEO par défaut, issus du groupe de paramètres site: et des paramètres emdash:site_title, emdash:site_tagline et emdash:locale

Elle omet :

  • Les comptes utilisateurs, les sessions, les passkeys, les données OAuth, les jetons d’API et les autres données d’authentification
  • Le stockage et les paramètres des plugins, y compris leurs secrets
  • Les commentaires et réactions, les redirections et journaux 404, les signatures (bylines), les relations et références de contenu, les journaux d’audit, les limites de débit et l’état des tâches planifiées
  • Les dossiers de médias, les enregistrements indiquant où les médias sont utilisés, les téléversements incomplets et les fichiers de médias eux-mêmes

Dans Settings → Backups, Download backup génère un nouveau fichier JSON. Back up now en stocke un sous le préfixe backups/ lorsque le stockage est configuré. Ces fichiers utilisent le même format d’instantané versionné que les aperçus d’EmDash.

Pour planifier des sauvegardes JSON, activez Daily automatic backups dans Settings → Backups et choisissez une rétention de 1 à 30 fichiers. Elles s’exécutent pendant la maintenance planifiée. Sur Cloudflare, le Worker a besoin d’un cron trigger ; sur Node, le planificateur intégré exécute la tâche.

Si le bucket a un domaine R2 public ou une origine de réseau de diffusion de contenu, limitez cette origine aux objets multimédias ou servez les médias via EmDash. La route média d’EmDash refuse de servir backups/, mais l’origine publique d’un bucket peut exposer chaque objet par son URL.

Pour copier le contenu, les paramètres et les médias vers un nouveau site EmDash, utilisez un paquet de site. Un paquet de site ne restaure pas les utilisateurs, les jetons d’API, les données des plugins ni les secrets ; il ne remplace donc pas un point de récupération de la base de données.