Skip to content

Backups and restore

Everything Day Planner stores (accounts, tasks, documents, settings) is in its Postgres database. Back that up and you can rebuild the whole instance.

This saves a compressed dump named with the current time.

Terminal window
docker compose exec -T db pg_dump -U dayplanner -d day_planner -Fc \
> day_planner-$(date -u +%Y%m%dT%H%M%SZ).dump

Check the file starts with PGDMP, the custom-format header:

Terminal window
head -c 5 day_planner-*.dump

Copy backups off the server. Run this from cron for regular backups.

A backup that’s never been restored isn’t a backup. This restores into a throwaway container and counts users:

Terminal window
docker run -d --name dp-restore -e POSTGRES_PASSWORD=restore -e POSTGRES_DB=day_planner postgres:16-alpine
sleep 5
docker cp day_planner-<timestamp>.dump dp-restore:/tmp/b.dump
docker exec dp-restore pg_restore -U postgres -d day_planner --no-owner --no-acl /tmp/b.dump
docker exec dp-restore psql -U postgres -d day_planner -Atc "select count(*) from users"
docker rm -f dp-restore

Compare the count, and those for tasks and documents, with the live database.

Restoring replaces the live data. Take a fresh backup first, and stop the app so nothing writes during the restore.

Terminal window
docker compose stop app
docker compose cp day_planner-<timestamp>.dump db:/tmp/b.dump
docker compose exec db pg_restore -U dayplanner -d day_planner --clean --if-exists --no-owner --no-acl /tmp/b.dump
docker compose start app

When the app starts, it applies any migrations the backup is missing.