AlgoJudge documentation0.2

What an installation is

Seven 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 labeled as development there; they are not this.

`0.2` 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.2 — the minor line this stack is written for, which takes every later patch on that line and nothing else. Not the moving major 0: below 1.0 a minor may change what the one before it did, so 0 would carry an installation across a break without asking. Update and rollback says how to pin a version more tightly still.

The services

Seven services under seven profile names. The Server and the Client carry two each, which is what lets one half be brought up without the other; the two Runners share one.

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-1, runner-2runnerone image, two identities, and the whole fleet. Each evaluates one submission at a time in sibling containers, several of that submission's tests at once
external-runnerexternal-runnerforwards them to an outside archive instead. Not in the default set — see An external judge

What has to fit the host is lanes, not Runners. A Runner judges as many of one submission's tests at once as RUNNER_TESTS_AT_ONCE says — one lane each — and a lane is one core's worth of work, so widening a Runner asks of the host exactly what adding one would. More lanes than physical cores does not judge faster and does stop judging accurately, which is why a host with capacity to spare raises RUNNER_TESTS_AT_ONCE rather than gaining a third Runner. 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 further arrangement. 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, checks out the release the application host runs, and runs COMPOSE_PROFILES=runner with two values in its .env:

SERVER_URL=https://your.domain
RUNNER_NAME_PREFIX=lab-a       # different on every host

That host needs Docker Engine 26 or later (Podman 5), and disk where Docker keeps its volumes: the Runners' cache and scratch live on the machine that judges, not on the application host. Below that engine a Runner refuses to judge, and there is no arrangement that avoids it — see Where the Runners keep their bytes.

The prefix names each Runner on the host — lab-a-1 and lab-a-2 — 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 home 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 two-Runner host is two 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