Skip to content

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.

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.

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 quizdock volume:

    Terminal window
    docker rm -f quizdock
    ./quizdock up

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.

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 .env keeps 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 .env lines, secrets left out, to make them permanent. qd settings.export prints them as JSON, the lines in env.
  • 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. write lets administrators change C2 to C4 values and run the instance operations.
  • ADMIN_LOCK names variables the web administration never changes, whatever the scope.
  • In local mode, the web administration changes nothing, the media library aside, until ADMIN_TOKEN is set (32 characters or more), and asks for it before any change.
  • ADMIN_OVERRIDES=ignore starts the instance on .env alone, 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.

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=true outside 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.

The reference below is generated from the settings of QuizDock 0.16.0.

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.

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.

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.

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.

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

Behind a reverse proxy, raise its request body limit above the largest of these sizes. See Reverse proxy.

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)
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.

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.

./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_ISSUER or OIDC_INTERNAL_URL in .env overrides 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 backup dumps it as keycloak.sql.
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.

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_user is 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.