In produzione, il problema non è fare il backup. Il problema è scoprirlo rotto quando serve davvero.
Questo articolo mostra una configurazione concreta per PostgreSQL 15 con pgBackRest, backup verificabili, restore testato e un hardening minimo dei permessi. L’obiettivo è semplice: ripristinare in fretta, senza lasciare il database più aperto del necessario.
Il caso tipico è questo: backup giornalieri presenti, ma restore lento, ruoli troppo larghi su public, e un test DR mai eseguito. Qui correggiamo proprio quel punto.
Prerequisiti
- PostgreSQL 15 su Linux.
- pgBackRest installato su server database e repository backup.
- Accesso da terminale come utente con privilegi sudo.
- Spazio disco separato per repository o bucket S3 compatibile.
- Una finestra di manutenzione per il primo test di restore.
Note: se usi Plesk o un pannello, la parte di PostgreSQL spesso è limitata. La configurazione di pgBackRest resta quasi sempre da riga di comando.
Step 1: separa ruoli e percorsi
La prima regola è non salvare il backup nello stesso volume dei dati. Se il disco si corrompe, perdi sia il database sia la copia.
Crea un utente dedicato e una directory di repository con permessi stretti.
sudo useradd --system --home /var/lib/pgbackrest --shell /usr/sbin/nologin pgbackrest
sudo mkdir -p /var/lib/pgbackrest /etc/pgbackrest /var/log/pgbackrest
sudo chown -R pgbackrest:pgbackrest /var/lib/pgbackrest /var/log/pgbackrest
sudo chmod 750 /var/lib/pgbackrest /var/log/pgbackrest
# Output: directory create e proprietà assegnata a pgbackrest
Per il database, controlla che il servizio PostgreSQL non scriva in una directory backup condivisa con altri servizi.
sudo -u postgres psql -c "SHOW data_directory;"
sudo -u postgres psql -c "SHOW config_file;"
# Output: percorsi di data_directory e config_file
Warning: non usare chmod 777 per “far funzionare” il backup. È un errore che torna utile solo ai problemi di sicurezza.
Step 2: configura pgBackRest per un profilo da produzione
La configurazione sotto punta a un repository locale. Se preferisci S3, il principio non cambia: cifratura, retention e verifica restano obbligatorie.
sudo tee /etc/pgbackrest/pgbackrest.conf > /dev/null <<'EOF'
[global]
repo1-path=/var/lib/pgbackrest
repo1-retention-full=7
repo1-retention-diff=14
log-level-console=info
start-fast=y
process-max=2
compress-type=zst
archive-async=y
archive-push-queue-max=8MB
[main]
pg1-path=/var/lib/postgresql/15/main
pg1-user=postgres
EOF
# Output: file di configurazione scritto in /etc/pgbackrest/pgbackrest.conf
Ogni parametro ha uno scopo preciso. compress-type=zst riduce spazio e tempi. archive-async=y aiuta l’archiving WAL. start-fast=y accelera il backup, ma va bene solo se il server ha margine I/O.
Se usi repository remoto, aggiungi cifratura lato backup. Con pgBackRest è meglio cifrare il repository che affidarsi solo alla rete.
sudo tee -a /etc/pgbackrest/pgbackrest.conf > /dev/null <<'EOF'
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=CAMBIA_QUESTA_PASSWORD_LUNGA
EOF
# Output: cifratura repository abilitata
Note: la password va conservata fuori dal server, in un secret manager o in un vault aziendale.
Step 3: limita i permessi su public e verifica i ruoli
Uno dei problemi più comuni in PostgreSQL è dare troppo a public. In produzione, il database deve essere prevedibile. Non “comodo”.
Controlla i privilegi correnti e rimuovi ciò che non serve.
sudo -u postgres psql -d appdb -c "\dn+"
sudo -u postgres psql -d appdb -c "REVOKE CREATE ON SCHEMA public FROM PUBLIC;"
sudo -u postgres psql -d appdb -c "REVOKE ALL ON DATABASE appdb FROM PUBLIC;"
# Output: privilegi ridotti su schema public e database
Se l’applicazione deve usare uno schema dedicato, assegna permessi espliciti al solo ruolo applicativo.
sudo -u postgres psql -d appdb -c "GRANT USAGE ON SCHEMA app TO app_user;"
sudo -u postgres psql -d appdb -c "GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA app TO app_user;"
sudo -u postgres psql -d appdb -c "ALTER DEFAULT PRIVILEGES IN SCHEMA app GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;"
# Output: ruolo app_user autorizzato solo sullo schema app
Questo evita il classico effetto collaterale: un restore andato bene, ma applicazione che poi scrive dove non dovrebbe.
Step 4: avvia un backup completo e controlla i WAL
Ora fai il primo backup completo. È il momento in cui scopri se la catena archivio-WAL funziona davvero.
sudo -u postgres pgbackrest --stanza=main stanza-create
sudo -u postgres pgbackrest --stanza=main backup
# Output: stanza creata e backup full completato
Subito dopo, verifica lo stato del repository.
sudo -u postgres pgbackrest --stanza=main info
# Output: almeno un backup full con stato ok
Se il backup fallisce con archiving sospeso, il problema è quasi sempre nel flusso WAL. In quel caso controlla i log PostgreSQL e il percorso di archiviazione.
sudo -u postgres psql -c "SHOW archive_mode;"
sudo -u postgres psql -c "SHOW archive_command;"
# Output: archive_mode attivo e archive_command configurato
Step 5: esegui un restore test in una directory separata
Il restore vero non va provato sul database di produzione. Va provato in una directory isolata, con un servizio temporaneo.
Ferma il cluster di test, prepara una directory vuota e ripristina lì dentro.
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/15/test-restore
sudo mkdir -p /var/lib/postgresql/15/test-restore
sudo chown postgres:postgres /var/lib/postgresql/15/test-restore
sudo -u postgres pgbackrest --stanza=main restore --pg1-path=/var/lib/postgresql/15/test-restore
# Output: dati ripristinati in /var/lib/postgresql/15/test-restore
Avvia un’istanza di test solo se il tuo ambiente lo consente. In alternativa, monta la directory ripristinata e controlla integrità e checksum applicativi.
Note: il comando di restore completo è spesso disponibile solo da terminale. Nei pannelli grafici di solito non c’è un test DR reale.
Step 6: rendi il restore ripetibile con un runbook
Il restore non deve vivere nella memoria di una sola persona. Serve un runbook breve, eseguibile in emergenza.
Un runbook utile contiene tre cose: ordine dei comandi, tempo atteso, criterio di ok.
restore_runbook:
stop_service: "systemctl stop postgresql"
verify_repo: "pgbackrest --stanza=main info"
restore_path: "/var/lib/postgresql/15/test-restore"
validate: "SELECT count(*) FROM pg_class;"
accept_if:
- "restore completed without errors"
- "database starts in less than 10 minutes"
- "application login works with app_user"
# Output: runbook salvato e condivisibile con il team
Un runbook scritto bene riduce errori sotto stress. È un dettaglio operativo, ma in incident response fa la differenza.
Step 7: pianifica backup automatici e retention
In produzione il backup manuale non basta. Serve una pianificazione fissa, con retention coerente e spazio monitorato.
Con systemd timer o cron, esegui un full settimanale e diff giornalieri. Se usi cron:
sudo tee /etc/cron.d/pgbackrest > /dev/null <<'EOF'
15 2 * * 1 postgres pgbackrest --stanza=main backup --type=full
15 2 * * 2-7 postgres pgbackrest --stanza=main backup --type=diff
EOF
# Output: backup schedulati con full il lunedì e diff gli altri giorni
Questo schema è semplice e prevedibile. La retention deve essere allineata alla capacità del repository e al RPO richiesto.
Se il repository è su S3
Con un bucket remoto, aggiungi almeno questi accorgimenti:
- bucket privato, mai pubblico;
- access key con privilegi minimi;
- versioning attivo;
- cifratura lato server o lato client;
- accesso solo da IP autorizzati, se possibile.
La sicurezza del backup è parte della sicurezza del database. Un backup leggibile da chiunque è un secondo incidente, non una protezione.
Verifica finale
La verifica finale deve essere pratica. Non basta vedere “success” nei log.
- Controlla che il repository contenga almeno un full e un diff recente.
- Conferma che il restore in directory separata sia andato a buon fine.
- Verifica che i privilegi su public siano stati ridotti.
- Simula l’accesso dell’app con il solo ruolo applicativo.
- Misura il tempo necessario per ripristinare un database di test.
Se vuoi un controllo rapido dei privilegi, usa questo comando:
sudo -u postgres psql -d appdb -c "\dp"
sudo -u postgres psql -d appdb -c "\dn+ public"
# Output: nessun privilegio eccessivo su public, accesso controllato ai soli ruoli previsti
Una buona baseline è questa: backup valido, restore testato, permessi ridotti, tempi misurati. Se manca uno di questi quattro punti, la configurazione non è ancora da produzione.
Troubleshooting
1) ERROR: [056]: archive-push command error: unable to open WAL file
Causa: PostgreSQL non riesce a scrivere o trovare i WAL per l’archiviazione.
Fix:
sudo -u postgres psql -c "SHOW archive_command;"
sudo tail -n 50 /var/log/postgresql/postgresql-15-main.log
sudo chown -R postgres:postgres /var/lib/postgresql/15/main
# Output: WAL access ripristinato e permessi corretti
2) ERROR: [082]: unable to load info file: permission denied
Causa: l’utente pgBackRest non ha accesso al repository o alla directory di log.
Fix:
sudo chown -R pgbackrest:pgbackrest /var/lib/pgbackrest /var/log/pgbackrest
sudo chmod 750 /var/lib/pgbackrest /var/log/pgbackrest
sudo -u postgres pgbackrest --stanza=main info
# Output: info repository leggibile e stato backup visibile
3) ERROR: permission denied for schema public
Causa: hai revocato i permessi a public, ma l’app usa ancora lo schema predefinito.
Fix:
sudo -u postgres psql -d appdb -c "ALTER ROLE app_user SET search_path = app, public;"
sudo -u postgres psql -d appdb -c "GRANT USAGE ON SCHEMA app TO app_user;"
# Output: l’app usa lo schema corretto senza toccare public in scrittura
Conclusione
Una configurazione seria di PostgreSQL non si misura dal numero di backup, ma dalla qualità del ripristino. pgBackRest aiuta molto, ma solo se il restore viene provato davvero.
Il prossimo passo concreto è fissare un restore test mensile con dataset realistico. Solo così saprai se il tuo piano di recupero regge il carico, i permessi e il tempo di fermo accettabile.
Commenti (0)
Nessun commento ancora.
Segnala contenuto
Elimina commento
Eliminare definitivamente questo commento?
L'azione non si può annullare.