Skip to content

Installation for production ​

This installation will download and use pre-built Docker images from a Docker Registry. Docker Compose is used to manage the images and set up networking, data persistence etc.

Prerequisites ​

Required software ​

Optional software ​

Make-scripts are used to control the app, i.e. starting, stopping. This can be done manually as well.

Installation ​

  • Download the installation script from the release page of the version you want to install. You can find the latest release here.

  • Run script

bash install.sh

Usage ​

Database setup ​

DB schema set up:

make testcenter-init

Run this once before the first start. make testcenter-update runs it for you as part of an update.

The command is safe to repeat: it applies only what is missing. Because it also reads the workspace files, it is likewise how you make the application notice files you placed in the data volume by hand.

Start & Stop ​

Run application in background

make testcenter-up

Run application with log infos in foreground

make testcenter-up-fg

Stop application

make testcenter-stop

Show log output

make testcenter-logs

Update ​

To update your installation to the lastest release, run

make testcenter-update

from the installation directory.

Backup and restore ​

An installation keeps its state in two places: the database (accounts, logins, test results) and the data files (units, booklets, testtaker files, resources). A backup is only usable if both halves come from the same moment, so back them up together:

make testcenter-backup

This writes one timestamped backup set into the installation directory, e.g.:

backup/2026-09-08T10-42-00Z/
├── iqb_tba_testcenter.sql   # the database
├── backend_vol.tar.gz       # the data files
└── manifest                 # version, database settings, checksums of both artifacts

The application may keep running while a backup is taken.

To restore a backup set, name it:

make testcenter-restore BACKUP=backup/2026-09-08T10-42-00Z
make testcenter-up

The restore checks the manifest first and refuses to start if an artifact is damaged or missing, or if the set was taken with a different DB_DATABASE or DB_USER than the installation is configured for - restoring such a set would not produce the installation it came from. It then stops the application, replaces both halves, and leaves the application stopped so you can start it yourself. Restoring replaces the data files: anything not contained in the backup is gone afterwards.

make testcenter-update takes such a backup set of its own before it changes anything, and it can be restored with the same command.

Disaster recovery on a new machine ​

  1. Install the same release the backup set was taken with (the release is recorded in the manifest; the restore warns if it does not match).
  2. Take DB_DATABASE, DB_USER and PASSWORD_SALT from the old .env.prod into the new one. The first two are recorded in the manifest, so the restore tells you if they do not match; the third is not, and see below for what happens without it. DB_PASSWORD is not one of them: it may be chosen anew, as long as it is set before the database starts for the first time.
  3. Copy the backup set into the backup directory of the new installation.
  4. Run make testcenter-restore BACKUP=backup/<set>, then make testcenter-up.

What a backup set does not contain ​

Your configuration - .env.prod, config/ and secrets/ - is not part of a backup set, so that a set holds no secrets and can be stored wherever your backups go. Keep a copy of the configuration separately. Without it a new installation cannot be reached under the same host name and TLS certificates, and three values from .env.prod have to match the set for a restore to produce the installation it came from:

  • DB_DATABASE and DB_USER are recorded in the manifest, and make testcenter-restore stops before it changes anything if either differs. Both can also be read out of the dump itself if the old .env.prod is gone: the database name from its CREATE DATABASE line, the user name from its OWNER TO lines.
  • PASSWORD_SALT cannot be recovered from a backup set - only a fingerprint of it is recorded, enough for the restore to warn that it differs. Test data, workspaces and testtaker logins are unaffected by the mismatch, but administrator accounts are not: their stored passwords belong to the other salt, and nobody can log in.

Recovering from that last case does not need the old salt. Give one system administrator a new password under the salt the installation now has, then use it to reset the remaining accounts in the web interface:

docker compose --env-file .env.prod --file docker-compose.yml --file docker-compose.prod.yml \
  run --rm --no-deps --entrypoint php backend \
  -r 'echo password_hash(hash_hmac("sha256", "NEW_PASSWORD", getenv("PASSWORD_SALT")), PASSWORD_BCRYPT, ["cost" => 10]), "\n";'

Then write the printed hash into the account, using make testcenter-connect-db:

UPDATE users SET password = '<hash>' WHERE name = 'super';

Restoring only one half ​

testcenter-dump-db, testcenter-restore-db, testcenter-export-backend-vol and testcenter-import-backend-vol work on a single half, by default in backup/temp, and accept BACKUP= like the commands above. Be aware that a database and data files from different moments do not match: workspaces whose content is missing stay empty, and the application says so during start-up.

Login ​

After installation two logins are prepared:

  • Username super and password user123 as admin user

  • Username test and password user123 and code xxx as test-taker

It is strongly advised to at least change the password under "System-Admin".

Configuration ​

Settings can be manipulated in the file .env.prod. Check after every update of the testcenter version, whether new configurations have been added to the .env.prod-template file, and consider adding them to your .env.prod file.

TLS ​

TLS Certificates can be managed manually or via a ACME provider like "Let's Encrypt" or "Sectigo". If you choose to use an ACME provider, the install process will ask for all necessary configuration data and fill in the .env file and create additional config files. If managed manually, the TLS certificate must be named certificate.pem and TLS Private Key must be named private_key.pem and both need to be placed in the folder /secrets/traefik/certs. If no certificates are configured, self-signed certificates are generated and used. This may cause a browser warning.

Database ​

The database runs as a container inside the application's own network and is not published to the host. It is configured by three settings in .env.prod:

DB_DATABASE=iqb_tba_testcenter
DB_USER=iqb_tba_db_user
DB_PASSWORD=<generated during installation>

The installation generates the password randomly. Host and port are not configurable: the backend always reaches the database as db on port 5432. The POSTGRES_* variables that the database image expects are derived from the three settings above; do not set them yourself.

DB_PASSWORD is only applied while the database is being created, during the very first start. Changing it in .env.prod afterwards does not change the password in the existing database, and the backend can no longer log in. Change it in both places:

make testcenter-connect-db
ALTER USER iqb_tba_db_user WITH PASSWORD 'new password';

Afterwards set the same value in .env.prod and restart the application with make testcenter-restart.

make testcenter-connect-db opens a psql prompt in the database container, for this and for any other database task. It works no matter what DB_PASSWORD says, because connections from inside the container need no password.

Cache service ​

The cache service is a Redis container (cache-server) inside the application's own network. It serves three purposes:

  • The file server checks every download of test resources against the group tokens the backend stores there.
  • Logins in the modes monitor-group and monitor-study are locked after 5 failed login attempts, until 30 minutes have passed since the last failed attempt. The backend counts the attempts in the cache service.
  • With REDIS_CACHE_FILES=true, the file server also keeps whole files there.

It is configured in .env.prod:

REDIS_PASSWORD=<generated during installation>
REDIS_MEMORY_MAX=1gb
REDIS_CACHE_FILES=false

Host and port are not configurable: the backend and the file server always reach the cache service as cache-server on port 6379.

The file server can be switched off with FILE_SERVER_ENABLED=false; the backend then delivers test resources itself. Only in that case can the backend run without the cache service, by leaving REDIS_PASSWORD empty. Failed login attempts are then not counted, so monitor logins are not locked.