AlgoJudge documentation0.1

What an installation is

Nine services, four arrangements, and one Compose file that chooses between them.

An AlgoJudge installation is a Docker Compose stack. It is delivered as its own repository, AlgoJudge-Ops, which you clone, configure through a .env file, and run.

That repository holds no application code and builds nothing. Every image is pulled by tag from GHCR, which is what makes an update docker compose pull and a rollback a digest. The Compose files that build from source live in the product repositories and are labelled as development there; they are not this.

`0` is the tag an installation asks for

The eight images are published and public: docker compose pull needs no registry login, from anywhere. What .env.example asks for is 0 — the moving major, which every 0.x release moves, breaking changes included. Update and rollback says what that costs and how to pin a version instead.

The services

Nine services, and seven profile names — the Server and the Client each carry two, which is what lets one half be brought up without the other.

ServiceProfilesWhat it is
postgresdataPostgreSQL 18. No host port, in any arrangement
serverapp, serverthe API at /api/v1, published on 127.0.0.1:8080
clientapp, clientthe browser application, published on 127.0.0.1:8082
nginxedgeTLS, one origin for both halves, ports 80 and 443
runner-1runner-4runnerone image, four identities. Each evaluates one submission at a time in sibling containers
external-runnerexternal-runnerforwards them to an outside archive instead. Not in the default set — see An external judge

Four is the reference, not a minimum. It suits eight physical cores and leaves four for everything else; on a smaller host run fewer, because more Runners than physical cores does not judge faster and does stop judging accurately. What the host needs has the table.

Three Compose networks carry them, so that the database is not reachable from the edge and evaluation traffic is separable from HTTP:

The Server is the only service on all three. PostgreSQL sits on backend alone and has no host port in any arrangement. Only nginx publishes a port to the network; the two loopback publications above exist for curl and for a proxy of your own.

The edge network is declared with an explicit subnet, 172.28.0.0/24 by default. That is not tidiness: the Server refuses to start until it has been told whose word to take for a visitor's address, and a subnet Docker picked at random could not be named.

The four arrangements

Chosen with COMPOSE_PROFILES in .env. No Compose file is edited for any of them.

COMPOSE_PROFILES
T1edge,app,data,runnerone host, the whole product. The default
T2edge,app,data, plus runner elsewhereRunners on their own machines
T3app,datayour own reverse proxy in front
client,server,dataone half at a time, for debugging and staged updates

external-runner is an addition to any of them, not a fifth one. Add it beside runner, or give it a machine of its own. It is outside the default set because it signs in to an outside archive under an account there — An external judge says what it needs and what it cannot do for you.

A Runner may live on another machine entirely

Each Runner host clones the same repository and runs COMPOSE_PROFILES=runner with three values in its .env:

SERVER_URL=https://your.domain
RUNNER_NAME_PREFIX=lab-a       # different on every host
RUNNER_WORK_DIR=/srv/algojudge/runner-work

The prefix names all four — lab-a-1 to lab-a-4 — and has to differ per host, or two machines' Runners appear in the panel under one set of names.

A Runner opens every connection itself. It needs no inbound port and works from behind a domestic router with no address of its own. It has no depends_on on the Server in compose.yaml, deliberately, because on a Runner-only host there is no Server service to depend on — it retries its own connection instead.

Each Runner registers separately and each needs its own approval, so a four-Runner host is four approvals.

T2 is the recommended arrangement for a public installation

Access to the Docker socket is equivalent to root on the host, and the Runner needs that socket to start job containers. In T1 the same host also holds the database, so anybody who escapes a job container is on the machine holding every submission and every password hash. On a Runner-only host the worst case is a machine that holds nothing.

What runs beside the stack, not inside it

An installation needs an OIDC provider, and neither supported identity deployment is a service in compose.yaml. It runs beside this stack, at its own hostname. Identity is the chapter for choosing and registering one.

Where to go next

What the host needsDocker, cgroup v2, disk, logs
First installfrom an empty directory to a verdict
Pre-configurationstanding one up without clicking through the panel
IdentityKeycloak or Authentik, and how to register one
Connecting a course platformLTI 1.3, and the browser setting it turns on
Where the files gothe three stores, and moving between them
Maintenance modetaking it out of service without stopping it
Backupwhat a dump covers, and what it carries
Restoreputting one back
Update and rollbackand what a rollback cannot undo
Routine work and the schedulegarbage collection, cron, and what nobody tells you
Your own reverse proxythe five rules
An external judgeforwarding problems to an outside archive
Every setting in .envthe whole of it, in one table
When something does not workthe failure modes that look like other problems

The source is in AlgoJudge-Ops. This project is licensed under MIT. See LICENSE. This documentation is CC BY 4.0.

On this page