Un punto di ripristino deve ripristinare l’intero database. I backup JSON di EmDash sono utili per l’ispezione e per strumenti personalizzati, ma EmDash non può ripristinarli. Prima di una migrazione del database o di un’operazione distruttiva, usa un backup grezzo del database o il point-in-time recovery.
Esegui il backup dei file binari dei media separatamente. Se il sito memorizza impostazioni di plugin cifrate, conserva l’intero elenco di rotazione di EMDASH_ENCRYPTION_KEY in un backup separato del gestore dei segreti. I backup e gli export del database non contengono quei file né quelle chiavi.
Scegliere un metodo di ripristino
Usa il metodo corrispondente all’adattatore di database configurato per il sito:
| Database | Punto di ripristino |
|---|---|
| Cloudflare D1 | Registra un bookmark di Time Travel. Crea un dump SQL offsite quando la conservazione richiesta supera quella di Time Travel o quando serve una prova di ripristino. |
| SQLite o libSQL locale | Usa il comando di backup online di SQLite, poi esegui un controllo di integrità sulla copia. |
| PostgreSQL | Usa il point-in-time recovery del provider oppure crea un archivio in formato custom con pg_dump. |
| Hyperdrive | Esegui il backup della sua origine PostgreSQL tramite una connessione diretta all’origine. Un binding Hyperdrive non è una connessione di backup. |
| libSQL ospitato su Turso | Usa il point-in-time recovery di Turso oppure crea e prova un dump SQL. |
| Altro provider libSQL remoto | Usa la procedura del provider per l’export dell’intero database o per il point-in-time recovery e provala su un database isolato. |
Conserva il punto di ripristino insieme all’artefatto dell’applicazione corrispondente, al backup dei media e alla versione dell’elenco delle chiavi. Prima di una migrazione pianificata, registra l’esatto database e ambiente, interrompi le scritture dell’applicazione quando la procedura del provider lo richiede e conferma che il punto di ripristino resti disponibile per l’intera finestra di rollback prevista.
Backup e ripristino degli oggetti media
I bucket R2 e compatibili con S3 richiedono un backup a livello di oggetto oltre a quello del database. Il seguente comando AWS CLI copia ogni oggetto, inclusi gli archivi JSON di EmDash sotto backups/, in una directory di backup locale. Per AWS S3, ometti --endpoint-url.
aws s3 sync s3://emdash-media ./emdash-media-backup \
--endpoint-url https://<account-id>.r2.cloudflarestorage.com
Sostituisci <account-id> con l’ID dell’account Cloudflare. Usa credenziali del bucket di sola lettura per i job di backup di routine. Conserva il backup fuori dall’account di produzione o dal dominio di guasto, e registra il punto di ripristino del database creato nello stesso momento.
Ripristina in un bucket di recupero vuoto invece di sovrascrivere la produzione mentre sta servendo richieste:
aws s3 sync ./emdash-media-backup s3://emdash-media-recovery \
--endpoint-url https://<account-id>.r2.cloudflarestorage.com
Dai al job di ripristino accesso in scrittura solo al bucket di recupero. Punta un deployment non di produzione al database e al bucket ripristinati, apri diversi URL di media noti, poi carica ed elimina un file usa e getta. Modifica il binding di produzione o la configurazione del bucket solo dopo che database e media hanno superato insieme i controlli.
Per lo storage locale, copia la directory configurata dall’adattatore di storage local(). Interrompi le scritture dei media durante la copia, poi verifica alcuni file rappresentativi della copia.
Recuperare un database D1 con Time Travel
Prima di una migrazione, chiedi a Time Travel il bookmark corrente del database e registra l’output completo insieme al deployment:
npx wrangler d1 time-travel info my-database
I punti di ripristino di Time Travel scadono. Cloudflare attualmente li conserva per 7 giorni sul piano Workers Free e per 30 giorni sul piano Workers Paid. Crea un dump D1 offsite quando la finestra di rollback deve durare più a lungo.
Se serve un recupero, interrompi le scritture sul sito e ripristina esattamente il bookmark registrato prima della migrazione:
npx wrangler d1 time-travel restore my-database \
--bookmark="<pre-migration-bookmark>"
Sostituisci <pre-migration-bookmark> con il bookmark registrato. Il comando sovrascrive il database sul posto e annulla le query in corso. Salva il bookmark precedente stampato dal comando di ripristino, così da poter annullare il ripristino stesso.
Time Travel ripristina contenuti, utenti, impostazioni, dati dei plugin e record di migrazione. Non ripristina gli oggetti media di R2 né EMDASH_ENCRYPTION_KEY. Ripristina l’artefatto dell’applicazione, i media e le chiavi corrispondenti prima di riaprire il traffico. Verifica l’accesso, la lettura dei contenuti, lo schema, un’impostazione di plugin cifrata e una scrittura.
Consulta la documentazione di D1 Time Travel per conoscere conservazione, requisiti e comportamento di ripristino attuali.
Creare un dump D1 offsite
Per un dump SQL del database grezzo (incluse le tabelle di utenti e autenticazione), usa Wrangler. Un semplice wrangler d1 export my-database --remote fallisce con D1 Export error: cannot export databases with Virtual Tables (fts5) non appena una collection ha la ricerca abilitata, perché EmDash mantiene il proprio indice di ricerca in tabelle virtuali FTS5. Esporta le altre tabelle per nome e lascia fuori l’indice di ricerca; il sito ripristinato lo ricostruisce.
Il dump è suddiviso in quattro file affinché il ripristino riesca:
backup-schema.sqlcrea le tabelle.backup-folders.sqlcontiene le cartelle dei media. Le importazioni di grandi dimensioni vengono eseguite a parti, quindi un elemento media verrebbe altrimenti inserito prima della cartella a cui appartiene e fallirebbe il controllo della chiave esterna.backup-data.sqlcontiene tutte le altre righe.backup-indexes.sqlcontiene gli indici e i trigger, che un export per nome di tabella lascia fuori. Vengono creati per ultimi, così i trigger non si attivano durante l’importazione delle righe.
Questi comandi richiedono jq. I comandi seguenti scrivono i quattro file:
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
D1 rifiuta le istruzioni SQL di 100.000 byte o più, e l’export scrive ogni riga come un singolo INSERT sulla propria riga. Una riga con un valore lungo, come una voce molto lunga o una delle sue revisioni, può superare quel limite. Controlla i file subito dopo averli creati. Il comando seguente stampa il file e la riga di ogni istruzione troppo lunga per D1, e non stampa nulla quando i file possono essere importati:
LC_ALL=C awk 'length($0) >= 100000 { print FILENAME ":" FNR }' backup-*.sql
Consulta la documentazione di import ed export di D1 per le opzioni e i limiti di export di Wrangler.
Conserva i file SQL insieme alla versione dell’applicazione corrispondente, al backup dei media creato nello stesso momento e a una copia, memorizzata separatamente, dell’elenco di rotazione di EMDASH_ENCRYPTION_KEY. Verifica il ripristino importando i file in un database D1 vuoto appena creato, ripristinando le chiavi di runtime, aggiornando un binding non di produzione verso quel database e controllando il sito.
Se il dump non è stato controllato quando è stato creato, esegui prima il controllo della lunghezza descritto sopra. Poi importa i file nel database di recupero vuoto in questo ordine:
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
Il database ripristinato non ha un indice di ricerca. EmDash lo ricostruisce la prima volta che l’API di ricerca (/_emdash/api/search) viene chiamata sul sito ripristinato, per esempio dalla palette dei comandi dell’amministrazione o da una casella di ricerca che usa l’API. Fino ad allora, le pagine che chiamano direttamente search() non restituiscono risultati. Per ricostruirlo subito, richiedi una volta /_emdash/api/search?q=a quando il sito è in esecuzione.
Backup di SQLite e libSQL locale
Per un backup offline, interrompi ogni processo che scrive nel database e copia il file del database insieme agli eventuali file -wal e -shm accanto a esso. Il file -wal può contenere modifiche confermate che non sono ancora nel file principale.
Per un backup online coerente, usa il comando di backup di SQLite sul percorso configurato dall’adattatore di database:
sqlite3 emdash.db ".backup backup.db"
Controlla il database copiato. Il comando deve stampare ok:
sqlite3 backup.db "PRAGMA integrity_check"
Apri la copia con la versione dell’applicazione corrispondente in un ambiente non di produzione e verifica l’accesso, i contenuti pubblici, un’impostazione di plugin cifrata, una modifica e una lettura di media.
Per recuperare, interrompi ogni processo che scrive nel database, conserva una copia del database danneggiato e dei suoi file -wal e -shm, sostituiscili con il backup verificato e ripristina l’artefatto dell’applicazione, i media e le chiavi corrispondenti prima di riaprire il traffico.
Backup di PostgreSQL e Hyperdrive
Usa il point-in-time recovery o la funzione di snapshot del provider PostgreSQL quando offre un ripristino isolato che si può testare prima di modificare la produzione. Registra l’esatto timestamp o ID dello snapshot e il periodo di conservazione.
Per un backup portabile, connettiti direttamente all’origine PostgreSQL e crea un archivio in formato custom:
pg_dump --format=custom --file=emdash.dump "$DATABASE_URL"
pg_dump crea un archivio coerente a livello transazionale mentre il database resta in uso. Ispeziona l’indice dell’archivio prima di farci affidamento:
pg_restore --list emdash.dump > emdash.dump.list
Predisponi un database di recupero vuoto. Connettiti con il ruolo applicativo canonico di EmDash e ripristina senza trasferire la proprietà dell’origine nel database di recupero:
pg_restore --exit-on-error --no-owner \
--dbname="$RECOVERY_DATABASE_URL" emdash.dump
Il ruolo in RECOVERY_DATABASE_URL diventa il proprietario degli oggetti EmDash ripristinati. Usa lo stesso ruolo stabile che userà l’applicazione recuperata. Punta un deployment non di produzione al database di recupero e verifica l’accesso, la lettura dei contenuti, lo schema, un’impostazione di plugin cifrata e una scrittura.
Per Hyperdrive, DATABASE_URL deve essere la connessione diretta all’origine PostgreSQL indicata da migrationConnectionStringEnv; il binding del Worker non può essere passato agli strumenti di backup di PostgreSQL. Segui la procedura di recupero del provider dell’origine e conserva la configurazione di Hyperdrive insieme all’artefatto dell’applicazione.
Consulta la documentazione sul backup di PostgreSQL per il recupero gestito dal provider, i database di grandi dimensioni e l’archiviazione continua.
Backup di libSQL ospitato su Turso
Il point-in-time recovery di Turso crea un database separato a partire da un timestamp precedente. Registra un timestamp RFC 3339 subito prima della migrazione. Se serve un recupero, crea un database isolato da quel punto:
turso db create emdash-recovery \
--from-db emdash-production \
--timestamp <pre-migration-rfc3339-timestamp>
Sostituisci <pre-migration-rfc3339-timestamp> con il timestamp registrato. Crea un token per il database recuperato, punta a esso un deployment non di produzione e verifica il sito prima di cambiare la connessione di produzione. Consulta il point-in-time recovery di Turso per la conservazione offerta dal piano del sito.
Per una copia offsite, esegui il dump dell’intero database:
turso db shell emdash-production .dump > emdash.sql
Verifica il dump creando da esso un database isolato:
turso db create emdash-recovery --from-dump ./emdash.sql
Per un altro provider libSQL remoto, segui la sua procedura di export dell’intero database o di point-in-time recovery. Non applicare una migrazione remota finché quella procedura non ha prodotto un punto di ripristino e un ripristino isolato non è stato testato.
Usare i backup JSON per l’ispezione
Un backup JSON include:
- Tutte le voci di contenuto, incluse bozze, post pianificati ed elementi nel cestino
- Le definizioni di collection e di campi che compongono il modello di contenuto
- Le definizioni di tassonomie, i termini e i termini assegnati a ciascuna voce
- Menu e voci di menu, sezioni, aree di widget e widget, record SEO, cronologia delle revisioni, metadati dei media e cronologia delle migrazioni del database
- Impostazioni del sito come titolo, tagline, URL, locale, logo, preferenze di visualizzazione, profili social e valori SEO predefiniti, dal gruppo di impostazioni
site:e dalle impostazioniemdash:site_title,emdash:site_taglineeemdash:locale
Omette:
- Account utente, sessioni, passkey, dati OAuth, token API e altri dati di autenticazione
- Lo storage e le impostazioni dei plugin, inclusi i segreti dei plugin
- Commenti e reazioni, redirect e log dei 404, byline, relazioni e riferimenti dei contenuti, log di audit, rate limit e stato delle attività pianificate
- Cartelle dei media, registri di dove vengono usati i media, caricamenti incompleti e i file multimediali stessi
- Altre opzioni del sito, tra cui
emdash:site_url, il segreto di firma delle anteprime e la pianificazione dei backup
In Settings → Backups, Download backup genera un nuovo file JSON. Back up now ne memorizza uno sotto il prefisso backups/ quando lo storage è configurato. Questi file usano lo stesso formato di snapshot versionato delle anteprime di EmDash.
Per pianificare i backup JSON, abilita Daily automatic backups in Settings → Backups e scegli una conservazione da 1 a 30 file. Vengono eseguiti durante la manutenzione pianificata. Su Cloudflare, il Worker ha bisogno di un cron trigger; su Node, lo scheduler integrato esegue l’attività.
Se il bucket ha un dominio R2 pubblico o un’origine di rete per la distribuzione dei contenuti, limita quell’origine agli oggetti media oppure servi i media tramite EmDash. La route dei media di EmDash rifiuta di servire backups/, ma l’origine pubblica di un bucket può esporre ogni oggetto tramite URL.
Per copiare contenuti, impostazioni e media in un nuovo sito EmDash, usa un pacchetto sito. Un pacchetto sito non ripristina utenti, token API, dati dei plugin né segreti, quindi non sostituisce un punto di ripristino del database.