Skip to main content
Back up PostgreSQL and nothing else. Every app, keyword, position, score, review, change event and action item lives there. Redis holds queue state, which is reconstructible: the next daily run rebuilds it. Including Redis in an application data backup adds size and restores nothing you need.

Take a backup

The block below writes a compressed custom format archive, fails on any error, and verifies that PostgreSQL can read its table of contents before declaring success.
umask 077 gives the archive restrictive permissions, which matters because the dump contains everything. Run it from the repository root with the same Compose project name the deployment uses. The default project name is the directory name. For a deployment started with docker compose -p production, add -p production to every command on this page.

Where does the data live?

In the named volume pgdata, mounted at /var/lib/postgresql in the postgres container. Compose prefixes it with the project name, so it appears as production_pgdata under a project called production. Copying the volume directory while PostgreSQL is running is not a backup. Use pg_dump, which produces a consistent snapshot.

Automate it

Put the block in a script and schedule it, keeping several generations.
Then prune old archives on whatever window your storage allows.
Keep tested generations off host. A backup on the same disk as the database survives a mistake but not a disk.
Never commit a database dump or a .env file to version control. Both contain credentials, and a dump contains every account record.

Verify a backup

A backup that has never been restored is not a backup. Schedule a real restore into a disposable stack on a regular cadence and confirm the app and keyword counts match. See Restore PostgreSQL.

Restore PostgreSQL

The other half of the drill.

Upgrade and roll back

Why the backup has to precede the upgrade.
Last modified on July 31, 2026