Configuration
QuizDock is configured with environment variables, without rebuilding anything. This page explains where they are read, who may change them, and lists every one of them.
Where the variables go
Section titled “Where the variables go”| How it runs | Where to set the variables |
|---|---|
./quizdock script |
.env in the instance’s folder (written by ./quizdock init) |
| Docker Compose by hand | .env next to docker-compose.prod.yml |
docker run (standalone) |
--env-file .env, or -e NAME=value flags |
| Docker Desktop | the container’s environment variables, set when it is created |
In Compose, docker-compose.prod.yml passes each application variable of the reference below to the container by name, except SAMPLES_DIR, and PORT, DATABASE_URL, REDIS_URL, MEDIA_DIR and STORE_DIR, which it sets to fixed values. A variable the Compose file does not list never reaches the application.
Apply a change made in .env
Section titled “Apply a change made in .env”Most variables are read at start. On the server, in the instance’s folder:
-
Compose and full: run
./quizdock up. Compose recreates the containers whose configuration changed. -
Standalone: the container keeps the environment it was created with. Recreate it; the data stays in the
quizdockvolume:Terminal window docker rm -f quizdock./quizdock up
Levels
Section titled “Levels”Every variable has a level, shown in the reference:
| Level | What it covers | Changed from the administration |
|---|---|---|
| C1 | Critical: start-up, data, security | Never: .env only |
| C2 | Access and resources | Yes, each change confirmed |
| C3 | Behaviour | Yes |
| C4 | Look and wording | Yes |
Each variable also says when a change applies: at once, at the next room a host opens, or at restart.
Changes made in the administration
Section titled “Changes made in the administration”An administrator can change C2 to C4 variables from Administration → Settings, or with qd settings.set. Such a change is an override:
- Precedence: the default, then
.env, then the administration. An override wins over.env, and.envkeeps its value underneath. - Storage: overrides are kept in the database, so they travel with a database backup and survive an upgrade.
- Way back: Back to .env for one variable, Take everything back for all, or
qd settings.reset --key=NAME(--all). Export as .env gives the overrides as.envlines, secrets left out, to make them permanent.qd settings.exportprints them as JSON, the lines inenv. - Audit: every change, and every refusal, is recorded. See Audit.
You decide how much the web administration may change:
ADMIN_WEB_SCOPE=read(the default) shows the settings and changes none of them.writelets administrators change C2 to C4 values and run the instance operations.ADMIN_LOCKnames variables the web administration never changes, whatever the scope.- In local mode, the web administration changes nothing, the media library aside, until
ADMIN_TOKENis set (32 characters or more), and asks for it before any change. ADMIN_OVERRIDES=ignorestarts the instance on.envalone, every override ignored but kept: the way out when an override went wrong.
These limits apply to the web. qd, run by whoever has access to the container, is not gated by ADMIN_WEB_SCOPE or ADMIN_LOCK, and never changes a C1 variable either. The quick setup in the wizard sets its answers as overrides too. See Settings and Presets.
Warnings at start
Section titled “Warnings at start”At start, the application logs a warning (context Settings) for every value it cannot use as written, and ./quizdock doctor lists the same ones:
- A value it cannot read (a typo, a wrong format): the default is used instead.
- A value outside its range: it is used as it is for now; a later release will enforce the range.
- Variables that contradict each other, for example
ALLOW_ANONYMOUS_PARTICIPANTS=trueoutside OIDC mode.
A problem on a C1 variable makes doctor fail. It is only a warning at start for now: from v1, an instance with an unreadable C1 variable will refuse to start. Fix what the log names before then. The Settings and Health pages of the administration show the same problems.
Environment reference
Section titled “Environment reference”The reference below is generated from the settings of QuizDock 0.16.0.
Identity & branding
Section titled “Identity & branding”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
APP_NAME
|
QuizDock |
1 to 40 characters | C4 | Brand name shown in the header, tab title and share text. Applies at once · changeable from the administration |
APP_LANG
|
en |
en · fr · es · zh · zh-TW · tr · de · hi · it · ja · pl · ru |
C4 | UI language for the instance, by default (no browser detection): anyone may pick their own, kept in their account or on their device; the projection speaks the quiz's language or the room's, and so does a player's phone unless they picked theirs. New quizzes start in this language; each quiz can be set to another in its settings. Applies at once · changeable from the administration |
APP_LOGO_URL
|
— | an https:// URL |
C4 |
Logo served from somewhere else (a CDN, a path outside branding/). Empty by default, which is the usual setup: the logo is then looked up in the mounted branding/ folder.
Applies at once
· changeable from the administration
|
APP_FEEDBACK_URL
|
— | an http(s):// URL, or none |
C4 |
Where the home page's Report a bug · Suggest a feature · Fix a translation · Ask a question links lead. Empty: the QuizDock repository, its forms filled in with the version, the browser and the language, and an invitation to star it on GitHub. Another GitHub repository (https://github.com/owner/repo): the same forms there — copy .github/ISSUE_TEMPLATE/ into it. Any other address: a single Send feedback link. none: no links.
Applies at once
· changeable from the administration
|
The logo, the icon and the stylesheet: see Branding.
Access & authentication
Section titled “Access & authentication”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
AUTH_MODE
|
none |
none · oidc |
C1 |
none = local mode (no IdP, single host seat); oidc = sign-in with any OpenID Connect provider, the session held by the backend.
Applies at restart
· .env only
|
DEMO_MODE
|
false |
true · false |
C1 |
true = public demo guards: every visitor shares one host account (demo_user), a host and an administrator by grant; the administration is shown read-only, media uploads are refused, and everything is wiped every hour — a reset waits, at most 3 hours, while a game is played.
Applies at restart
· .env only
|
DEMO_STATS_URL
|
— | an https:// URL, no trailing slash | C1 |
With DEMO_MODE=true and DEMO_STATS_TOKEN: where the public demo counts its page views, starts and time on page (the Cloudflare Worker of tools/demo-stats), with no cookie and no personal data — a day-salted hash and a country only. Unset, or outside a demo: nothing is counted, nothing leaves.
Applies at restart
· .env only
|
DEMO_STATS_TOKEN
|
— | text, 32 characters or more | C1 |
The token the demo gives the statistics Worker (DEMO_STATS_URL), the same as its STATS_TOKEN secret. At least 32 characters.
Applies at restart
· .env only
|
ALLOW_ANONYMOUS_PARTICIPANTS
|
false |
true · false |
C2 |
AUTH_MODE=oidc only: true lets hosts open a game to participants without an account, the PIN and a nickname alone — chosen at each launch.
Applies at once
· changeable from the administration
· set by the quick setup (audience)
|
OIDC_ISSUER
|
— | an http(s):// URL, without query or fragment |
C1 |
iss expected in tokens (your provider's issuer URL). Required when AUTH_MODE=oidc.
Applies at restart
· .env only
|
OIDC_CLIENT_ID
|
quiz-dock-frontend |
text | C1 | The client registered with your provider. Applies at restart · .env only |
OIDC_CLIENT_SECRET
|
— | text | C1 | Its secret, for a confidential client. Unset: a public client, protected by PKCE. Applies at restart · .env only |
OIDC_INTERNAL_URL
|
(host of OIDC_JWKS_URI) |
an http(s):// URL |
C1 |
Where the backend reaches the provider when the browser's address is not reachable from its network (Docker): discovery, tokens and keys go through it. Defaults to the host of OIDC_JWKS_URI when that one points elsewhere than the issuer.
Applies at restart
· .env only
|
OIDC_JWKS_URI
|
(discovery) | an http(s):// URL |
C1 | Key endpoint, when discovery's must not be used. Applies at restart · .env only |
OIDC_AUDIENCE
|
— | text | C1 |
Expected aud. Left unset = audience check skipped.
Applies at restart
· .env only
|
OIDC_ROLES_CLAIM
|
roles |
a dotted path | C1 |
Dotted path to the roles array in the JWT (e.g. groups, realm_access.roles). A typo locks every administrator out.
Applies at restart
· .env only
|
OIDC_NAME_CLAIM
|
— | a dotted path | C3 |
Dotted path to the display-name claim (e.g. the standard nickname). Unset, or absent from a token: preferred_username, then name, then email.
Applies at once
· changeable from the administration
|
How to connect a provider, and what open access means: see Sign-in with OpenID Connect. DEMO_MODE is described in Public demo instance.
Network & invitation
Section titled “Network & invitation”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
PORT
|
3000 |
a port | C1 |
In-container HTTP port. Map it to a host port (-p 18080:3000).
Applies at restart
· .env only
|
TRUST_PROXY
|
(private addresses) | false, true, a number of proxies, or addresses and CIDR ranges |
C1 |
Which hops may speak for the client through X-Forwarded-For / X-Forwarded-Proto (client address of the wrong-PIN limit, Secure session cookie). Default: a peer on a private address.
Applies at restart
· .env only
|
APP_PUBLIC_URL
|
— | an http(s):// URL, without path |
C3 | Public address of the instance. Offered first as the invitation address (QR code, join link) on the host console. Applies at once · changeable from the administration |
HOST_LAN_IPS
|
— | comma-separated IPv4 addresses | C3 | Comma-separated LAN IPs of the machine (bare IPs), for setups where the container cannot see the host's interfaces (Docker Desktop, bridge network). Offered as invitation addresses with the scheme and port of the page. Applies at once · changeable from the administration |
QUIZ_STORE_URL
|
(disabled) | up to five comma-separated http(s):// URLs |
C2 | Comma-separated registry URLs of the community catalogue. Leave unset or empty to hide the community page and prevent all outgoing store requests. Enabling contacts the listed services from the server: its IP is visible, no user data is sent. Applies at once · changeable from the administration |
QUIZ_STORE_HOSTS
|
github.com,release-assets.githubusercontent.com |
comma-separated host names | C2 | Additional exact host names allowed for source indexes, artifacts and redirects. Registry hosts are allowed automatically. Empty: the registry hosts only. Applies at once · changeable from the administration |
UPDATE_CHECK
|
true |
true · false |
C4 |
The administration and quizdock status say when a newer stable release of QuizDock is out: the server asks GitHub (api.github.com) once a day, an hour later after a failure. Nothing is installed: the update stays ./quizdock upgrade. GitHub sees the server's IP and, in the request's User-Agent, its version; nothing else is sent.
Applies at once
· changeable from the administration
· set by the quick setup (internet)
|
Which address the QR code carries in each setup, and what reaches the Internet: see Networking.
Storage
Section titled “Storage”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
DATABASE_URL
|
— (required) | a PostgreSQL URL | C1 |
PostgreSQL connection string, e.g. postgresql://user:pass@host:5432/quizdock. Required (provided by Compose; baked into :standalone).
Applies at restart
· .env only
|
REDIS_URL
|
— (provided by Compose) | a Redis URL | C1 |
Redis connection string, e.g. redis://host:6379. It holds the live games, and also the browser sessions under OIDC, the setup wizard's, the confirmations and the rate limits: a Redis that loses its data ends the games in progress and signs everyone out.
Applies at restart
· .env only
|
MEDIA_DIR
|
/data/media (images) |
a path | C1 | Where uploaded images, videos and sounds are stored. Mount a volume here to persist. Applies at restart · .env only |
STORE_DIR
|
/data/store (images) |
a path | C1 |
Where the catalogue of shared templates lives: index.json plus one folder per template, in the bundle format. Its own volume, like MEDIA_DIR — back it up with the database, it is not in PostgreSQL. The sample quizzes are seeded here at start.
Applies at restart
· .env only
|
SAMPLES_DIR
|
/app/samples (images) |
a path | C1 |
Where the image keeps the sample quizzes it ships: one bundle folder each, with their media. At its first start an instance also adds those media to the instance's media, unless an administrator already curates that library; a .samples-media marker in MEDIA_DIR keeps them from coming back once removed.
Applies at restart
· .env only
|
MEDIA_DIR and STORE_DIR are not in PostgreSQL: back them up with the database, at the same moment. See Back up an instance.
Limits
Section titled “Limits”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
MEDIA_MAX_BYTES
|
10485760 |
bytes, 1 to 50 MB | C2 | Max size of an uploaded image, in bytes. Default 10 MiB. Applies at once · changeable from the administration |
MEDIA_MAX_VIDEO_MB
|
50 |
1 to 500 (MB) | C2 | Max size of an uploaded video, in MB. The editor converts to MP4 H.264 + AAC and compresses a long video to fit. Applies at once · changeable from the administration |
MEDIA_MAX_AUDIO_MB
|
10 |
1 to 100 (MB) | C2 | Max size of an uploaded sound, in MB. The editor converts to M4A (AAC). Applies at once · changeable from the administration |
IMPORT_MAX_BYTES
|
52428800 |
bytes, 1 to 500 MB | C2 | Max size of an imported quiz bundle (zip), in bytes. Default 50 MiB. Applies at once · changeable from the administration |
PUBLICATION_MAX_MB
|
20 |
1 to 100 (MB) | C3 | Largest bundle the editor's Export for publication allows, in MB: the limit of the community store, kept under GitHub's 25 MB web-upload limit. An organisation running its own store may set another. Applies at once · changeable from the administration |
MEDIA_LIBRARY_LINKS
|
(seven free libraries) | a JSON list, or none |
C4 |
The free media libraries the editor links to: a JSON list of {"name", "url", "kinds"} (kinds among image, video, audio), or none to hide them (an instance without Internet). Default, open licences only and several per kind: OpenSoundLibrary, Freesound, ccMixter, Openverse, Wikimedia Commons, NASA Image and Video Library, Internet Archive.
Applies at once
· changeable from the administration
· set by the quick setup (internet)
|
Behind a reverse proxy, raise its request body limit above the largest of these sizes. See Reverse proxy.
Game pace
Section titled “Game pace”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
GAME_READ_DELAY_MS
|
3000 |
0 to 10000 (ms) | C3 | Reading window shown before a question's timer starts, in milliseconds. Applies at once · changeable from the administration · set by the quick setup (accessibility) |
GAME_ALL_ANSWERED_DELAY_MS
|
1000 |
0 to 5000 (ms) | C3 | Once every participant has answered, how long the question stays before its answer is revealed, in milliseconds. Applies at once · changeable from the administration · set by the quick setup (accessibility) |
GAME_AUTO_ADVANCE_MS
|
5000 |
1000 to 60000 (ms) | C3 | Automatic mode: time spent on a reveal or a content slide before moving on, unless the question or slide sets its own, in milliseconds. Applies at once · changeable from the administration |
GAME_MEDIA_WAIT_S
|
10 |
0 to 60 (s) | C3 |
How long the room waits at most, before a question, for the devices that play its sound or video to load it (the host can start anyway), in seconds. 0 never waits.
Applies at once
· changeable from the administration
· set by the quick setup (audience)
|
LIVE_MOTION
|
on |
on · off |
C4 |
Transitions between steps on the projection and the phones, as a new room starts: the previous background fades out, the step comes in, the standings slide. off for old projectors or low-end devices. The host switches it for their room at any time (console, Animations); a device asking the system to reduce motion keeps fades only.
Applies next room
· changeable from the administration
· set by the quick setup (accessibility)
|
Administration
Section titled “Administration”| Variable | Default | Accepts | Level | Description |
|---|---|---|---|---|
ADMIN_WEB_SCOPE
|
read |
read · write |
C1 |
What the web administration may change in the Instance domain (settings, accounts, host seat): read shows everything and changes nothing; write lets administrators change the C2–C4 settings and run the instance operations, each critical one confirmed. Media and quizzes are not concerned.
Applies at restart
· .env only
|
ADMIN_LOCK
|
— | comma-separated variable names | C1 |
Variables the web administration may never change, whatever ADMIN_WEB_SCOPE says: comma-separated names (e.g. APP_NAME,MEDIA_MAX_VIDEO_MB). The CLI is not concerned.
Applies at restart
· .env only
|
ADMIN_TOKEN
|
— | text, 32 characters or more | C1 |
Local mode (AUTH_MODE=none) has no accounts, so whoever reaches the instance could administer it: the web administration changes nothing there — the media library aside — unless this token is set, and asks for it before any change. At least 32 characters: a shorter one is ignored, as if unset.
Applies at restart
· .env only
|
ADMIN_OVERRIDES
|
apply |
apply · ignore |
C1 |
ignore starts the instance on its environment alone: every value changed from the web administration is ignored (kept, not deleted) — the way back when one of them went wrong.
Applies at restart
· .env only
|
What the web administration does with these: see the administration overview.
Deployment (Compose)
Section titled “Deployment (Compose)”Read by docker-compose.prod.yml and the ./quizdock script, never by the application.
| Variable | Default | Level | Description |
|---|---|---|---|
HTTP_PORT
|
18080 |
C1 | Host port mapped to the app. |
QUIZDOCK_TAG
|
latest |
C1 |
Image tag to run (0.4.0 to pin).
|
POSTGRES_USER
|
live |
C1 |
Bundled PostgreSQL user (builds DATABASE_URL).
|
POSTGRES_PASSWORD
|
live |
C1 | Its password. |
POSTGRES_DB
|
quizdock |
C1 | Its database. |
QUIZDOCK_DB_USER
|
quizdock from init; unset = the database superuser |
C1 |
QuizDock's own PostgreSQL role: it owns the application's database and nothing else, the superuser (POSTGRES_USER) kept for administering PostgreSQL. Set at install; an existing install gets it from quizdock db:roles, which moves the database to it.
|
QUIZDOCK_DB_PASSWORD
|
Generated by init |
C1 |
Password of QUIZDOCK_DB_USER.
|
KEYCLOAK_DB_USER
|
keycloak from init --full; unset = the database superuser |
C1 |
The bundled Keycloak's own PostgreSQL role: its database belongs to it, and it reaches nothing of QuizDock's. Set at install; an existing install gets it from quizdock db:roles, which moves Keycloak's database to it.
|
KEYCLOAK_DB_PASSWORD
|
Generated by init --full |
C1 |
Password of KEYCLOAK_DB_USER.
|
QUIZDOCK_MODE
|
compose |
C1 |
What the quizdock script runs: compose, standalone or full.
|
Bundled Keycloak (full)
Section titled “Bundled Keycloak (full)”./quizdock init --full downloads docker-compose.full.yml, used on top of the Compose file. Only this overlay derives the application and OIDC addresses from PUBLIC_HOST; the other setups ignore it.
| Variable | Default | Level | Description |
|---|---|---|---|
PUBLIC_HOST
|
localhost |
C1 | Full preset: browser-facing hostname or LAN IP for both services. |
PUBLIC_SCHEME
|
http |
C1 |
Full preset: URL scheme; use https behind a TLS reverse proxy.
|
KEYCLOAK_PORT
|
18081 (full), 18080 (dev) |
C1 | Keycloak's published HTTP port. |
KEYCLOAK_BIND
|
127.0.0.1 (dev) |
C1 | Dev: the address Keycloak's port is published on, this computer only by default (its admin is admin/admin). To sign in from another device, an address it reaches (a Tailscale one rather than the whole LAN), with KEYCLOAK_PUBLIC_URL, OIDC_ISSUER and KEYCLOAK_DEV_URL on it. |
KEYCLOAK_PUBLIC_URL
|
Scheme, host and Keycloak port | C1 | Override the browser-facing Keycloak URL (full preset: including a proxy path; dev: the address another device reaches it on). |
KEYCLOAK_APP_URL
|
Scheme, host and app port (full) | C1 |
Override the app URL allowed for browser redirects. Dev also allows localhost:15173, and defaults to localhost:18081.
|
KEYCLOAK_DEV_URL
|
http://localhost:15173 (dev) |
C1 |
Additional dev frontend redirect, alongside KEYCLOAK_APP_URL. The full preset uses only KEYCLOAK_APP_URL.
|
KEYCLOAK_ADMIN
|
admin |
C1 | Keycloak bootstrap administrator. |
KEYCLOAK_ADMIN_PASSWORD
|
Generated by init --full |
C1 | Bootstrap administrator password; replace the manual example before first start. |
KEYCLOAK_HOST_PASSWORD
|
Generated by init --full |
C1 |
Initial temporary full-preset host password; dev always uses animateur.
|
KEYCLOAK_PLAYER_PASSWORD
|
Generated by init --full |
C1 |
Initial temporary full-preset player password; dev always uses participant.
|
- An explicit
APP_PUBLIC_URL,OIDC_ISSUERorOIDC_INTERNAL_URLin.envoverrides what the full setup derives. - Keycloak imports the realm only into an empty database: changing the initial passwords later does not reset existing accounts. Use the Keycloak administration console for that.
- Keycloak’s database,
keycloak, lives in the same PostgreSQL server../quizdock backupdumps it askeycloak.sql.
Ports and volumes
Section titled “Ports and volumes”| Compose and full | Standalone | |
|---|---|---|
| Application, in the container | port 3000 |
port 3000 |
| Published on the server | HTTP_PORT (18080) |
the -p you give (18080 with the script) |
| Keycloak (full) | KEYCLOAK_PORT (18081) |
— |
| PostgreSQL and Redis | on an internal Docker network, not published | inside the container, on 127.0.0.1 only |
| Database | volume pgdata |
volume quizdock, at /data/postgres |
| Live state (Redis) | volume redisdata, append-only file on |
in memory only |
Media (MEDIA_DIR) |
volume mediadata, at /data/media |
volume quizdock, at /data/media |
Templates folder (STORE_DIR) |
volume storedata, at /data/store |
volume quizdock, at /data/store |
| Branding folder | ./branding mounted at /app/client/branding (commented out in the Compose file) |
-v "$PWD/branding:/app/client/branding:ro" |
Compose prefixes its volume names with the project name: quizdock_pgdata, quizdock_mediadata, and so on.
Public demo instance
Section titled “Public demo instance”DEMO_MODE is not local mode. AUTH_MODE says who may host: anyone with a name, or an OIDC account. DEMO_MODE=true says the instance is open to strangers, and adds guards on top. It is meant for the standalone image in local mode, without a volume, as on the live demo. The guards:
- One shared host account,
demo_user. Whatever name a visitor gives, the server serves that account, which holds the host seat without expiry. Everyone sees and changes the same quiz bank; visitors may step on each other’s quizzes and games. The sign-in page is a single Enter the demo button. - Read-only template catalogue. The sample templates can be previewed and copied, but sharing and withdrawing templates are refused.
- No media uploads, including imported quizzes that carry media.
- Hourly reset to a blank instance: accounts, quizzes, media, archived games, the host seat and the live state. Then
demo_useris created again, with the sample quizzes in its bank. A reset waits while a game is being played, for at most 3 hours. The template catalogue is never reset.
The pages show a banner, and the home page lists these guards, ending with the fact that a self-hosted instance has none of them. On the standalone image, the list adds that image’s own limits.