Webmaster
How openCBT is deployed, and what runs where.
For whoever runs the servers. The school-facing guide is at /docs; this section assumes Linux, Docker and DNS are familiar.
What exists
| Deployment | DEPLOYMENT_TARGET | Sits exams | Owns the structure | Syncs |
|---|---|---|---|---|
| A school's own server | onsite | yes | yes | starts every transfer |
| A school's cloud companion | cloud | no | no, copied up | answers the school |
| A school entirely online | full-cloud | yes | yes | nothing to sync |
One image serves all three; the environment decides which it is. Papers, results and marks move only when somebody presses a button on the school's Cloud Sync page — the cloud never initiates anything, because it cannot reach inside a school's network.
The pieces
- The image:
ghcr.io/reelmza/opencbt, built by GitHub Actions on every push tomain, tagged with the commit andlatest. Private, so every server needs a read-only token to pull it. deploy/in the repository: one compose file per deployment, the Caddy configuration for the cloud, and the backup and restore scripts.- One database per school. Never shared, on any deployment.
/dataon each server: uploaded pictures, exports, session archives and backups.
Pages here
The cloud VPS
Hetzner, Caddy, and adding a school's cloud companion.
Releases and updates
How the image is built, how a server is updated, and how to roll one back.
Restoring a backup
The procedure, and what it costs.
A school entirely online
The full-cloud deployment, for a school with no hall server.
Conventions worth keeping
One token per box. A read-only read:packages token each, so losing a
school's server means revoking one token, not all of them.
Pin the image on a school's server. OPENCBT_IMAGE in its .env, set to a
commit or a version tag, so an exam morning is never the first time that box
runs a new build.
The clocks matter. Signed transfers are rejected if the two servers'
clocks are more than five minutes apart. systemd-timesyncd is enough.