# WyOJ -- one-command deployment. # # docker compose up -d --build # fresh install (creates ./uoj_data) # ./judger/register-judger.sh # register the judger in judger_info # docker compose -f docker-compose.yml -f docker-compose.seed.yml up -d # # ... and seed the bundled production dump # docker compose logs -f uoj-web # apache + install output # docker compose logs -f uoj-judger # judge_client output # docker exec -it uoj-web bash # shell inside the web container # # Layout: # ./db/ uoj-db image: MySQL 5.7 + the current schema (app_uoj233.sql) # ./web/ uoj-web image: apache + php 7.4 + the WyOJ sources (+ judger tree) # ./judger/ uoj-judger image: python judge_client + the C++ sandbox # ./uoj_data/ runtime state (mysql datadir, /var/uoj_data, app/storage) # # `version` is kept so this still parses with the legacy python docker-compose; # service readiness is handled by install.sh's own wait loop, not by # depends_on conditions, for the same reason. # # SECURITY: the three secrets below are placeholders that are published in this # repository. Change JUDGER_PASSWORD / JUDGER_SOCKET_PASSWORD / the database # password together (and re-run ./judger/register-judger.sh) before putting this # anywhere public. version: '3' services: uoj-db: image: uoj-db:latest build: context: ./db/ dockerfile: Dockerfile container_name: uoj-db restart: always volumes: - ./uoj_data/db/mysql:/var/lib/mysql environment: - MYSQL_DATABASE=app_uoj233 - MYSQL_ROOT_PASSWORD=root healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-proot"] interval: 10s timeout: 5s retries: 12 start_period: 30s uoj-web: image: uoj-web:latest build: # root context: the web image also needs ./judger (see web/Dockerfile) context: ./ dockerfile: web/Dockerfile container_name: uoj-web restart: always depends_on: - uoj-db volumes: # DEV: mount the sources so edits take effect per-request instead of # requiring an image rebuild. Remove this line for a production deploy. - ./web:/opt/uoj/web # uploads and .UOJSetupDone -- must persist across recreates - ./uoj_data/web/data:/var/uoj_data # submissions / pastes / tmp / judge_client.zip - ./uoj_data/web/storage:/opt/uoj/web/app/storage # generated on first boot from the environment below; kept on the host so # that rebuilding the image does not lose it - type: bind source: ./.config.local.php target: /opt/uoj/web/app/.config.php ports: - "80:80" # 3690 was published by the original file but nothing listens on it. # - "3690:3690" environment: - DATABASE_HOST=uoj-db - DATABASE_NAME=app_uoj233 - DATABASE_USER=root - DATABASE_PASSWORD=root - JUDGER_SOCKET_PORT=2333 - JUDGER_SOCKET_PASSWORD=_judger_socket_password_ - SALT_0=_salt_0_ - SALT_1=_salt_1_ - SALT_2=_salt_2_ - SALT_3=_salt_3_ - UOJ_PROTOCOL=http uoj-judger: image: uoj-judger:latest build: context: ./judger/ dockerfile: Dockerfile container_name: uoj-judger restart: always depends_on: - uoj-web # run_program.cpp drives the sandbox with ptrace(); without SYS_PTRACE the # first submission fails with "Judgement Failed". If the sandbox still # misbehaves under docker's default seccomp profile, add: # security_opt: ["seccomp:unconfined"] cap_add: - SYS_PTRACE volumes: # main_judger reads problem data directly instead of downloading it # (judge_client skips update_problem_data for judger_name == main_judger), # so share the web's data directory with it. - ./uoj_data/web/data:/var/uoj_data_copy:ro environment: - UOJ_PROTOCOL=http - UOJ_HOST=uoj-web - JUDGER_NAME=main_judger - JUDGER_PASSWORD=_judger_password_ - JUDGER_SOCKET_PORT=2333 - JUDGER_SOCKET_PASSWORD=_judger_socket_password_ # No ports: the web reaches this container over the compose network via the # service name (`uoj-judger`), which is also what judger_info.ip must hold.