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.shKnow 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 workerThe 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 verifiedSession 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.