Backup e ripristino
Panoramica
Sezione intitolata “Panoramica”Rebase esegue il backup di un database Postgres con pg_dump e lo ripristina
con pg_restore. Puoi creare un backup manualmente, pianificarne uno con un
cron job, elencare quelli disponibili dalla CLI o dal pannello Backups di
Studio, e ripristinare in un database nuovo senza toccare quello attivo.
Avvio rapido
Sezione intitolata “Avvio rapido”# Esegui il backup in una cartella locale (formato personalizzato, compresso)rebase db backup --out ./backups
# Esegui il backup direttamente su object storage privatorebase db backup --out s3://my-private-bucket/backups
# Elenca i backup disponibilirebase db backups list --out ./backups
# Ripristina in un database NUOVO (non toccando quello attivo)rebase db restore ./backups/rebase-app-20260714T030000Z.dump \ --create-db --target-db app_restoredLa stringa di connessione proviene dall’ambiente del tuo progetto, come per
ogni altro comando rebase db: DATABASE_URL, con fallback su
ADMIN_CONNECTION_STRING.
Cos’è un backup
Sezione intitolata “Cos’è un backup”rebase db backup esegue pg_dump in formato personalizzato (-Fc), che è
compresso e può essere ripristinato selettivamente. I file vengono nominati
rebase-<db>-<YYYYMMDD>T<HHMMSS>Z.dump; il timestamp UTC nel nome è ciò su
cui si basano l’ordinamento e la retention.
| Opzione | Descrizione |
|---|---|
--out, -o |
Un percorso locale, o un URL s3://bucket/prefix / gs://bucket/prefix. Il valore predefinito è $BACKUP_DESTINATION, poi ./backups. |
--exclude-schema <s> |
Esclude uno schema dal dump (ripetibile). Non escludere mai rebase — vedi sotto. |
--no-owner |
Omette i comandi di proprietà, per ripristinare come un ruolo diverso. |
--enable-row-security |
Esegue il dump come soggetto admin invece di fallire sulla row-level security. Può produrre un dump parziale — vedi Row-level security. |
--row-security-role <r> |
Il ruolo con cui leggere con il flag sopra. Il valore predefinito è admin. |
Un dump viene validato prima che il comando segnali il successo:
pg_restore --list deve riuscire a leggere l’intero archivio.
Per le destinazioni s3:// la CLI costruisce il proprio client di storage
dalle stesse variabili S3_* usate dal tuo backend (S3_ACCESS_KEY_ID,
S3_SECRET_ACCESS_KEY, S3_REGION, S3_ENDPOINT, S3_FORCE_PATH_STYLE).
Il file dei ruoli
Sezione intitolata “Il file dei ruoli”Ogni backup scrive un secondo file accanto al dump:
rebase-<db>-<…>Z.globals.sql, prodotto da
pg_dumpall --globals-only --no-role-passwords. Un pg_dump per singolo
database non può includere i ruoli a livello di cluster, e i grant e le
policy di row-level security del dump ne nominano uno — rebase_user.
Ripristinato in un nuovo Postgres senza di esso, il primo GRANT verso quel
ruolo fallisce e il ripristino si interrompe.
Mantieni i due file insieme. La CLI li carica, elenca, pota e ripristina come
coppia, e rebase db restore cerca il .globals.sql nella stessa cartella o
prefisso del .dump. I ruoli vengono ricreati senza password;
impostale di nuovo dopo un ripristino in un nuovo cluster. PG_DUMPALL_PATH
indica un binario pg_dumpall specifico.
Cosa contiene
Sezione intitolata “Cosa contiene”Tutto il database, incluso lo schema rebase. Quello schema contiene ogni
account utente e il resto dell’autenticazione, le chiavi API, la cronologia
dei record, la coda dei job, i log dei cron, e le funzioni richiamate dalle
tue policy RLS e dai trigger di change-capture. Un dump senza di esso non ha
utenti, e non può essere ripristinato in un database vuoto: le tabelle che
contiene hanno policy che richiamano funzioni che non contiene.
Backup pianificati
Sezione intitolata “Backup pianificati”Un backup pianificato è un cron job che esegue il
dump del database, carica il risultato su BACKUP_DESTINATION e pota i
backup vecchi. Inserisci un file in backend/crons/ che esporti come
default:
// backend/crons/backup.tsimport { GCSStorageController, S3StorageController, type StorageController } from "@rebasepro/server";import { createBackupCron, backupCronConfigFromEnv } from "@rebasepro/server-postgres";
const resolved = backupCronConfigFromEnv(process.env);if (resolved.error) throw new Error(resolved.error);
function backupStorage(): StorageController | undefined { const destination = resolved.config?.destination; if (destination?.kind === "gcs") { return new GCSStorageController({ type: "gcs", bucket: destination.bucket }); } if (destination?.kind !== "s3") return undefined; // local: written to disk directly return new S3StorageController({ type: "s3", bucket: destination.bucket, region: process.env.S3_REGION || "auto", accessKeyId: process.env.S3_ACCESS_KEY_ID ?? "", secretAccessKey: process.env.S3_SECRET_ACCESS_KEY ?? "", endpoint: process.env.S3_ENDPOINT, forcePathStyle: process.env.S3_FORCE_PATH_STYLE === "true" });}
// With BACKUP_SCHEDULE unset, export a disabled job so discovery still works.export default resolved.config ? createBackupCron({ ...resolved.config, storage: backupStorage() }) : createBackupCron({ schedule: "0 3 * * *", connectionString: process.env.DATABASE_URL ?? "", destination: { kind: "local", path: "./backups" }, enabled: false });Il controller di storage viene passato invece di essere preso dal contesto
del job, perché rebase.storage nel contesto è l’API di storage lato
client, non un controller per il bucket dei backup.
| Variabile | Significato |
|---|---|
BACKUP_SCHEDULE |
Espressione cron, ad es. 0 3 * * * per le 03:00 ogni giorno. Non impostata disattiva i backup pianificati. |
BACKUP_DESTINATION |
Un percorso locale, o s3://bucket/prefix / gs://bucket/prefix. |
BACKUP_RETENTION_DAYS |
Elimina i backup più vecchi di questo numero di giorni. Non impostata o 0 mantiene tutto. |
BACKUP_KEEP_MINIMUM |
Mantiene sempre almeno questo numero di backup recenti, per quanto vecchi — così un’interruzione prolungata non elimina tutto. |
Ogni nuovo dump viene validato prima che qualcosa venga potato, quindi un dump corrotto non può mai essere il motivo per cui il tuo ultimo backup valido è stato eliminato. La potatura tocca solo i file il cui nome corrisponde al pattern dei backup; qualsiasi altra cosa che condivide il bucket o il prefisso resta intatta.
Il cron esegue pg_dump all’interno del processo server.
l’immagine di
runtime ufficiale (rebasepro/server, vedi
Self-hosting) include a questo scopo gli
strumenti client di PostgreSQL 18;
sulla 0.23 e precedenti non ne aveva alcuno, e ogni esecuzione pianificata
falliva con Could not find the 'pg_dump' binary. Ovunque altrove — un VPS,
una tua immagine — installa tu stesso gli strumenti client (vedi la sezione
successiva).
Compatibilità delle versioni
Sezione intitolata “Compatibilità delle versioni”pg_dump e pg_restore devono avere la stessa versione major del server,
o una più recente. Ogni comando verifica prima la versione major del
client rispetto al server_version_num del server attivo e si interrompe
con il rimedio se non corrispondono, o se il binario è assente:
✗ Client tool is Postgres 15 but the server is Postgres 16. pg_dump/pg_restore must be the same major version as the server or newer. Install Postgres 16 client tools.Installali con brew install libpq o
apt-get install postgresql-client-18 (dal repository apt di PostgreSQL,
dove quello di Debian è più vecchio), oppure indica un binario specifico con
PG_DUMP_PATH, PG_RESTORE_PATH e PG_DUMPALL_PATH.
Row-level security, e il dump silenziosamente incompleto
Sezione intitolata “Row-level security, e il dump silenziosamente incompleto”Su un Postgres gestito — Cloud SQL, RDS e gli altri — non esiste un
superuser da concedere, quindi il ruolo con cui ti connetti di solito non
possiede nessuna delle tue tabelle e non ha BYPASSRLS. La row-level
security si applica anche a lui, e pg_dump si rifiuta:
pg_dump: error: query failed: ERROR: query would be affected by row-levelsecurity policy for table "company_leads"Quel rifiuto è l’esito sicuro. Aggiungere --enable-row-security a pg_dump
manualmente è quello pericoloso: ha successo, esce con 0, e il dump contiene
silenziosamente solo le righe che le policy del ruolo che esegue il dump
ammettono. Due vie d’uscita reali:
-
Concedi al ruolo che esegue il dump
BYPASSRLS, oppure rendilo proprietario delle tabelle. Il dump contiene allora ogni riga.ALTER ROLE my_backup_role BYPASSRLS; -
rebase db backup --enable-row-security. Rebase impostaapp.uideapp.user_rolesin modo che la policy generataadmin_full_accessammetta il dump, e stampa un avviso che indica cosa hai scambiato: una tabella le cui policy non includono alcuna regola admin risulta incompleta, e nulla lo segnala.
Ripristino
Sezione intitolata “Ripristino”rebase db restore <backup> [--target-db <name>] [--create-db] [--clean] [--yes]restore esegue pg_restore, ed è un’operazione distruttiva, quindi non è
mai automatica: senza --yes richiede una conferma interattiva yes, e in
una shell non interattiva si interrompe. <backup> è un .dump locale o una
chiave s3://… / gs://…, scaricata per prima.
Prima di ripristinare, ricrea i ruoli del cluster a partire dal
.globals.sql del backup — un ruolo già esistente viene saltato, non è un
errore — in modo che i grant e le policy del dump si applichino. Esegue poi
con --exit-on-error: un ripristino che registrasse un GRANT fallito e
continuasse segnalerebbe successo con la row-level security non applicata.
Senza un .globals.sql accanto al backup avvisa che alcuni ruoli potrebbero
mancare.
| Opzione | Descrizione |
|---|---|
--target-db <name> |
Ripristina in questo database invece di quello in DATABASE_URL. |
--create-db |
Crea prima il database di destinazione se non esiste. |
--clean |
Elimina gli oggetti esistenti prima di ricrearli (--clean --if-exists). |
--no-owner |
Ignora la proprietà registrata nel dump. |
--continue-on-error |
Registra gli errori e continua oltre di essi. Può lasciare la RLS non applicata; usalo solo quando sai perché. |
--yes, -y |
Salta la conferma. |
La procedura sicura è ripristinare accanto al database attivo, verificarlo, e solo dopo spostare l’app:
rebase db restore <backup> --create-db --target-db app_restored- Punta un processo di prova (o
psql) suapp_restorede verifica i conteggi delle righe, un accesso, e le tabelle a cui tieni più. - Ripunta
DATABASE_URLsu di esso, oppure rinomina i database, durante una breve finestra di manutenzione. - Ripristina i tuoi file caricati dal loro backup proprio, allo stesso momento nel tempo quanto più possibile.
Il pannello Backups
Sezione intitolata “Il pannello Backups”Il pannello Backups di Studio, nel gruppo Database, elenca i backup
presenti in BACKUP_DESTINATION, dal più recente, con la loro dimensione e
l’orario. Download scarica il dump; Roles file scarica il suo
.globals.sql. Scarica entrambi e conservali nella stessa cartella. Un
backup contrassegnato No roles file non ha il file collaterale: ricrea i
suoi ruoli a mano prima di ripristinarlo in un nuovo Postgres.
sopra l’elenco viene mostrato il job di backup pianificato e la sua ultima esecuzione. Un’esecuzione fallita viene mostrata come errore con il proprio messaggio, così un backup notturno che non riesce a eseguirsi è visibile dove sono elencati i backup, non solo nel pannello Cron Jobs.
ecco cosa riporta sul job:
- Last scheduled backup è l’ultima esecuzione fatta dalla pianificazione. Un’esecuzione avviata a mano da allora (Run Now in Cron Jobs) ha una riga a sé, così un’esecuzione di prova riuscita non può nascondere un backup notturno fallito, e una fallita non viene riportata come il backup notturno.
- Un job dichiarato
enabled: falserisulta come backup pianificati off. È ciò che esporta il file di cron qui sopra finchéBACKUP_SCHEDULEnon è impostata, e impostareBACKUP_SCHEDULEli attiva. Paused significa che un admin ha messo in pausa il job in Cron Jobs, e riprenderlo lì lo riattiva. - Un job che lo scheduler ha rifiutato, per una pianificazione, un fuso orario o un timeout non validi, viene riportato con il motivo. Non viene mai eseguito finché il suo file di cron non viene corretto.
- Quando la cronologia delle esecuzioni in
rebase.cron_logsnon può essere letta, il pannello lo dice, anziché dire che il backup non è ancora stato eseguito.
l’elenco viene letto
dal processo server che risponde a GET /api/admin/backups, e non sempre è
il processo che esegue la pianificazione:
- Una destinazione
s3://viene elencata e scaricata tramite un client per quel bucket, costruito dalle stesse variabiliS3_*usate dal cron di backup. Unags://usa le credenziali predefinite dell’applicazione (ADC). Forniscile a ogni processo che serve/api/admin, compreso il ruoloapidi un deployment suddiviso, non solo a quello che esegue il cron. Una destinazione che il processo non riesce a leggere risponde503con la destinazione e il motivo, e il pannello mostra questo anziché un elenco vuoto. - Un percorso locale è il disco proprio di quel processo. Quando la pianificazione viene
eseguita in un altro processo (un
apiconREBASE_CRON_SCHEDULER=falseaccanto a unworker), il pannello dice che sta elencando il disco di questo processo: i backup pianificati compaiono lì solo se entrambi i processi montano la stessa directory. Un deployment suddiviso dovrebbe fare il backup su object storage.
I download passano attraverso
GET /api/admin/backups/download?key=…, riservato agli admin, così il
bucket non deve mai essere pubblico; una chiave fuori dal prefisso della
destinazione viene rifiutata. Con BACKUP_DESTINATION non impostata, il
pannello indica che i backup non sono configurati.
Mantieni i backup privati
Sezione intitolata “Mantieni i backup privati”Un backup contiene tutti i tuoi dati, credenziali e dati personali inclusi.
- Non usare mai un bucket pubblico. Mantieni il suo accesso privato e registralo nei log.
- Attiva la cifratura at-rest: la server-side encryption di S3, la cifratura predefinita di GCS, o la cifratura del disco per una cartella locale.
- Limita chi può leggere la posizione dei backup, e ruota le sue credenziali.
- Preferisci un bucket dedicato, separato dai file caricati dagli utenti.
Point-in-time recovery
Sezione intitolata “Point-in-time recovery”Un backup pg_dump si ripristina al momento in cui è stato eseguito il
dump. Recuperare a un secondo qualsiasi nel mezzo richiede l’archiviazione
dei WAL e backup di base, che la distribuzione open source non esegue per
te. Se ti serve in self-hosting, esegui pgBackRest o wal-g accanto al tuo
Postgres e mantieni questi dump come una seconda copia, portabile.