Skip to content

Backups, and what to do when something falls over

Three things, and only the first is unrecoverable:

What Where If you lose it
The database Postgres You have lost everything: orders, customers, products
Uploaded images the backend’s static/ Product pages with no photos, and they do not regenerate
Cache and queues Redis Nothing. It rebuilds itself

Under Docker these are the db, static and redis volumes.

Terminal window
pg_dump -Fc "$DATABASE_URL" > store-$(date +%F).dump

Compressed format (-Fc) because it lets you restore individual parts.

Put it in a daily cron and keep it off the server. A copy on the same machine does not protect against the case that happens most: losing the machine.

Restoring:

Terminal window
pg_restore --clean --no-owner -d "$DATABASE_URL" store-2026-08-04.dump

Any update that touches the database deserves a backup right before, even if you have the daily one. The daily one is from this morning; the migration is from now.

Terminal window
pg_dump -Fc "$DATABASE_URL" > pre-migration-$(date +%F-%H%M).dump
npm run preparar # applies whatever the schema is missing and prepares the shop

preparar takes a lock in Postgres: two servers starting at once do not step on each other applying the same migration. And it deletes nothing: if something fails, the database stays as it was and the backup is still there just in case.

Photos uploaded from the panel go to the static/ folder, which in the container is a separate volume. On purpose: if they lived next to the code, every update would wipe them. When you back up, back up that volume too — the database stores the URLs, not the images.

A backend that falls over at 4am does not report itself. A checker every few minutes that looks at whether the store responds and restarts it if not costs ten lines and saves the customer’s phone call asking why their site has been erroring for hours.

Two things that help if you use pm2:

  • Growing wait between restarts. If the database restarts — the system’s automatic updates do it overnight — the backend goes down and, without a wait, relaunches in a loop dozens of times per incident.
  • Log rotation, or the file grows without limit until it fills the disk.
  • Does the backup actually restore? A backup that has never been tested is not a backup, it is a file.
  • Is it off the server?
  • How much data are you willing to lose? That decides whether the backup is daily or hourly.