openCBT

Restoring a backup

The procedure, and what it costs.

Restoring replaces the database and the uploaded pictures with a backup's contents. It is not a button in the app, because it has to happen with openCBT stopped and because it destroys anything entered since that backup was taken.

Before you touch anything

Take a fresh backup, even of a database you believe is broken. It is the only way back if this restore turns out to be the wrong choice.

cd ~/deploy
docker compose -f compose.onsite.yml run --rm backup /scripts/backup.sh

Know what you are giving up. Everything after the backup's timestamp goes: if a day of exams happened since, those sittings go with it. When only one paper is wrong, re-entering it by hand is often the smaller loss.

The procedure

cd ~/deploy

# 1. what is available
docker compose -f compose.onsite.yml run --rm backup /scripts/restore.sh

# 2. stop the app and the worker; leave the database running
docker compose -f compose.onsite.yml stop app worker

# 3. restore, naming the backup
docker compose -f compose.onsite.yml run --rm backup \
  /scripts/restore.sh 2026-09-24-0100 --yes

# 4. start again
docker compose -f compose.onsite.yml start app worker

The script checks the dump can be read before it drops anything, then restores in a single transaction: either all of it lands or none does. The pictures are extracted afterwards; their names are content hashes, so overwriting is safe.

Then check /api/health and sign in.

Restoring from a downloaded file

A backup that was downloaded from Settings arrives as opencbt-backup-<name>.tar.gz. Put it back where backups live, then restore as above:

# copy it into the app's volume via the backup service
docker compose -f compose.onsite.yml run --rm -v "$PWD:/incoming" backup \
  -c 'tar xzf /incoming/opencbt-backup-2026-09-24-0100.tar.gz -C /data/backups'

Restoring onto a different machine

Same procedure, with two extra steps: the new box needs the same .env (DATABASE_URL password included, or the restored database will refuse its own credentials), and the hall's saved address should be given to the new machine so nothing else has to change.

A cloud companion

The same commands with compose.cloud.yml, from that school's directory. There is a shortcut, though: a cloud's structure, papers and results are all copies of the school's. A cloud that has lost its database is often quicker to rebuild from the school — bring it up empty, then press Send everything, Send results and (if essays were being marked there) Send essays on the school's Cloud Sync page. Marks given on the cloud and not yet brought down are the one thing that cannot be recovered that way.

What a backup contains

2026-09-24-0100/
  database.dump    pg_dump custom format: everything
  media.tar.gz     uploaded pictures and the school logo
  MANIFEST         when, how many tables, sizes, and that it verified

Session archives live on /data too and are included in backups taken after them. Once a session has been purged, its archive file is the only copy of that detail — guard it accordingly.

On this page