Ubuntu 22.04 安装 DOMJudge 9.0.1 指南
在 Ubuntu 22.04 上从零源码安装 DOMjudge 9.0.1(domserver+judgehost+chroot 沙箱)的完整实测指南:PHP8.3/PPA、configure root 拒绝、unix_socket 建库、judgedaemon 绑核 systemd 托管与端到端 AC 判题验证,含在线/离线两方案对比与 8 条排障实录。
Ubuntu 22.04 安装 DOMJudge 9.0.1 指南
目标:在 Ubuntu 22.04 LTS 服务器上从零安装一套完整可用的 DOMjudge 9.0.1 竞赛评测系统(domserver 网站端 + judgehost 评测机 + chroot 评测沙箱),并完成比赛创建、团队提交、自动判题的端到端验证。已在 Ubuntu 22.04(PHP 8.3 + MariaDB 10.6 + nginx 1.18)环境实测通过,含全程排障实录。
一、环境信息
本文所有命令与回显均在以下真实环境实测(2026-10-28):
- 操作系统:Ubuntu 22.04 LTS(GNU/Linux 5.15,x86_64)
- DOMjudge:9.0.1(官方 tarball 源码安装,安装前缀
/opt/domjudge) - Web 服务:nginx 1.18.0 + PHP-FPM 8.3.36(ppa:ondrej/php)
- 数据库:MariaDB 10.6.23
- 编译器/语言:gcc/g++(12.x)、OpenJDK 11、Python 3.10
- 角色拓扑:单机同时承担 domserver 与 judgehost(1 核绑定的 judgedaemon),生产多机拆分方式见第七节
- 监听端口:80/tcp(nginx,DOMjudge 站点前缀
/domjudge/) - 关键目录:
/opt/domjudge/domserver(网站端)、/opt/domjudge/judgehost(评测机)、/chroot/domjudge(评测沙箱)
版本核实说明:官方最新稳定版以 domjudge.org 首页 Download 徽章为准,2026-10-28 实查为 9.0.1。系统架构与选型背景见 《DOMJudge 介绍与选型指南》。
二、前置条件
DOMjudge 是「网站端 + 评测机」双角色系统,安装前先确认以下条件全部满足,任一缺失都会导致后续步骤中断。
- 一台具有 root 权限的 Ubuntu 22.04 服务器:评测沙箱(chroot 构建、系统调用限制)与 systemd 单元安装都需要 root;官网 about 页明确要求「至少一台拥有 root 权限的 Linux 机器」。
- PHP ≥ 8.2.0 及指定扩展:官方管理员手册对 9.0 系列要求 PHP 8.2 以上,扩展含
curl、ds、gd、intl、json、mbstring、mysqli、xml、zip。Ubuntu 22.04 官方源只有 PHP 8.1,必须先接入 ppa:ondrej/php(见 4.2 节实测排障)。 - MariaDB 或 MySQL:可与本机同机部署(本文采用),官方对 9.0 的要求见手册;MariaDB 10.6 实测可用。
- nginx 或 Apache:本文用 nginx;Apache 配置片段官方同样随包提供(
etc/apache.conf)。 - 评测语言编译器:按需安装 gcc/g++、OpenJDK、Python3 等,它们同时要装进 chroot 沙箱(4.8 节)。
- sudo、debootstrap、acl 等 judgehost 依赖:judgedaemon 的 runguard 包装器依赖 sudo 提权完成 chroot 切换。
- 可用的软件下载渠道:官方 tarball 位于 domjudge.org,若直连缓慢可用代理(4.3 节有实测降级记录)。
确认系统版本与核心组件在位的验证命令:
lsb_release -ds && uname -m
实测回显:
Ubuntu 22.04.5 LTS
x86_64
三、版本选型说明
安装前需要确定三件事:装哪个版本、从哪里拿、装成什么形态。
| 项目 | 结论(2026-10-28 实查) | 说明 |
|---|---|---|
| 最新稳定版 | 9.0.1 | domjudge.org 首页 Download 徽章 |
| 上一稳定线 | 8.3.2 | 官方下载页仍提供 |
| 获取渠道 | https://www.domjudge.org/releases/domjudge-9.0.1.tar.gz | 官方 releases 目录 |
| Ubuntu apt 仓库 | 无 domjudge 包 | apt-cache policy domjudge 实测无输出 |
| 安装形态 | 源码 tarball 编译安装 | 官方手册唯一主线方式 |
两点关键差异解读:
- apt 装不了:Ubuntu 22.04 官方源未收录 DOMjudge,
apt-cache policy domjudge无任何候选版本(实测),所以「apt install domjudge」这条路在 Ubuntu 22.04 上不存在,编译安装是唯一官方路径。 - PHP 版本必须升级:Ubuntu 22.04 自带 PHP 8.1,不满足 9.0 系列要求的 ≥8.2.0,需通过 ppa:ondrej/php 安装 8.3。这个差异不是可选项,是硬门槛(4.2 节实测验证)。
💡 技术拓展:竞赛评测系统的「安装形态」不止编译安装一种。常见获取渠道对比——
渠道 特点 适用场景 源码 tarball 编译 官方主线,版本最新,可控前缀 生产赛事部署(本文方案) 发行版 apt 包 免编译,但 Ubuntu 22.04 未收录 此路不通,仅作事实说明 打包发行形态 官方提供 domserver/judgehost 预打包发行物,启动快 快速体验与临时赛 源码 git 检出 含最新特性但有开发态依赖 二次开发、贡献代码 本文实际采用「源码 tarball 编译」,理由是它是官方手册唯一完整支持的安装路径,且版本与官网稳定版严格一致。
四、在线安装方案 A(官方 tarball 源码编译)
本章是完整主线:依赖 → 下载 → 编译 → 数据库 → Web 服务 → 评测机 → 沙箱 → systemd 托管 → 端到端验证。每一步都给出实测命令与真实回显。
4.1 方案说明与整体流程
方案 A 面向可联网的服务器:从官方 releases 地址下载 9.0.1 tarball,编译出 domserver(网站端)与 judgehost(评测机)两个角色并安装到 /opt/domjudge,随后初始化数据库、配置 nginx/PHP-FPM、构建评测 chroot 沙箱,最后以 systemd 托管 judgedaemon 并完成端到端判题验证。整体顺序不可颠倒:数据库初始化依赖编译产物,chroot 依赖 debootstrap,judgedaemon 启动依赖前两者。
4.2 安装系统依赖
先安装 domserver 侧依赖(nginx、MariaDB、PHP 8.3 及扩展、composer),再补 judgehost 侧依赖(sudo、debootstrap、acl 等)。Ubuntu 22.04 的 PHP 8.1 不满足要求,第一步先接入 ppa:ondrej/php:
export DEBIAN_FRONTEND=noninteractive
add-apt-repository -y ppa:ondrej/php
apt-get update
apt-get -y install build-essential make gcc g++ autoconf automake \
composer php8.3-cli php8.3-mysql php8.3-zip php8.3-gd php8.3-curl \
php8.3-intl php8.3-mbstring php8.3-xml php8.3-fpm php8.3-ds php8.3-bcmath \
nginx mariadb-server acl sudo debootstrap lsof procps \
openjdk-11-jdk-headless default-jre-headless linux-libc-dev \
curl wget unzip git
实测回显(节选,apt-get 输出很长,保留关键配置段与版本确认):
Setting up nginx (1.18.0-6ubuntu14.22) ...
Setting up mariadb-server (1:10.6.23-0ubuntu0.22.04.1) ...
Setting up composer (2.2.6-2ubuntu4) ...
装完立即验证三个核心组件版本,这一步同时确认 PHP 已升到 8.3:
php -v | head -1
mariadbd --version
nginx -v
实测回显:
PHP 8.3.36 (cli) (built: Oct 21 2026 14:31:50) (NTS)
mariadbd Ver 10.6.23-MariaDB-0ubuntu0.22.04.1 for debian-linux-gnu on x86_64 (Ubuntu 22.04)
nginx version: nginx/1.18.0 (Ubuntu)
⚠️ 排障实录:若跳过 PPA 直接用 Ubuntu 22.04 源安装,得到的是 PHP 8.1(实测
PHP 8.1.2-1ubuntu2.28)。后续编译虽能通过,但 domserver 运行时会出现兼容性问题(9.0 的 webapp 基于 Symfony 6.4,要求 PHP ≥ 8.2)。正确做法是如上先加ppa:ondrej/php再安装php8.3-*全家桶,其中php8.3-ds与php8.3-bcmath是 DOMjudge 官方点名的扩展,容易漏装。
4.3 下载官方 tarball
从官方 releases 目录下载 9.0.1 源码包,包体约 55.5MB。先直连官方源,缓慢或超时再切换代理(本文实测直连速率约 100KB/s 不满足使用,切代理后约 3.8MB/s):
cd /root
curl -fLO --max-time 300 https://www.domjudge.org/releases/domjudge-9.0.1.tar.gz
实测回显(输出节选,实测首尾):
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 55.5M 0 95517 0 0 47369 0 0:20:29 0:00:02 0:20:27 47379
11 55.5M 11 6741k 0 0 1737k 0 0:00:32 0:00:03 0:00:29 1737k
32 55.5M 32 18.0M 0 0 3816k 0 0:00:14 0:00:04 0:00:10 3816k
⚠️ 网络说明:实测环境直连 domjudge.org 速率仅约 100–170KB/s(预计 5 分钟以上且中途超时被截断),改走代理
http://192.168.1.62:7897后速率升至约 3.8MB/s 并完整下载 55.5MB。当前实测可用渠道:直连慢、代理可用,内网部署请按「官方源 → 国内源 → 代理」的降级链自行选择。使用代理的命令形态:curl -fLO --max-time 300 -x http://192.168.1.62:7897 https://www.domjudge.org/releases/domjudge-9.0.1.tar.gz。
解压并进入源码目录:
cd /root
tar xzf domjudge-9.0.1.tar.gz
cd domjudge-9.0.1
ls
实测回显(节选):
CODINGSTYLE.md CONTRIBUTING.md CONTRIBUTORS.md COPYING COPYING.BSD
COPYING.MIT ChangeLog Makefile Makefile.global README.md aclocal.m4
bootstrap codecov.yml config.guess config.sub configure configure.ac
coverity doc etc judge lib ...
4.4 编译与安装(domserver + judgehost)
DOMjudge 的编译分两段:configure 生成构建配置,make 分角色构建。先执行 configure 指定安装前缀与运行用户:
cd /root/domjudge-9.0.1
./configure --prefix=/opt/domjudge --with-domjudge-user=domjudge
实测回显(节选,configure 检查项很多,保留关键结论行):
checking for gcc... gcc
checking for gcc option to enable C11 features... none needed
checking domjudge-user... domjudge
checking for php... yes
config.status: creating paths.mk
config.status: creating etc/config.h
⚠️ 排障实录:以 root 执行 configure 时会直接报错拒绝——实测报错原文为
checking domjudge-user... configure: error: installing/running as root is STRONGLY DISCOURAGED, use --with-domjudge-user=root to override.。这是官方的强约束:DOMjudge 拒绝以 root 作为评测运行用户。正确做法是先创建普通用户domjudge(useradd -m domjudge),再用--with-domjudge-user=domjudge显式指定;若强行指定--with-domjudge-user=root也可以通过 configure,但评测进程将以 root 运行,官方强烈不建议。
编译两个角色的构建目标(-j$(nproc) 按 CPU 数并行):
make domserver judgehost -j$(nproc)
实测回显(节选,保留构建起点与典型编译命令行):
make[1]: Entering directory '/root/domjudge-9.0.1/etc'
Substituting configure variables in 'apache.conf'.
Substituting configure variables in 'nginx-conf'.
Substituting configure variables in 'nginx-conf-inner'.
Substituting configure variables in 'domjudge-fpm.conf'.
Substituting configure variables in 'domserver-static.php'.
...
gcc -g -O2 -Wall -Wformat -Wformat-security -pedantic -fstack-protector -fPIE -D_FORTIFY_SOURCE=2 -std=c11 -DREVISION="\"release\"" -I/root/domjudge-9.0.1/lib -I/root/domjudge-9.0.1/etc -o evict evict.c /root/domjudge-9.0.1/lib/lib.error.c /root/domjudge-9.0.1/lib/lib.misc.c
安装到 /opt/domjudge(root 权限会自动设置密码文件与目录属主):
make install-domserver install-judgehost
实测回显(节选):
/usr/bin/install -c -d /opt/domjudge/domserver/bin /opt/domjudge/domserver/etc /opt/domjudge/domserver/lib /opt/domjudge/domserver/log /opt/domjudge/domserver/run /opt/domjudge/domserver/webapp/public/images/affiliations /opt/domjudge/domserver/webapp/public/images/countries /opt/domjudge/domserver/webapp/public/images/teams /opt/domjudge/domserver/example_problems /opt/domjudge/domserver/db-dumps
...
========== Judgehost Install Completed ==========
Optionally:
- Install the create-cgroup service to setup the secure judging restrictions:
cp judge/create-cgroups.service /etc/systemd/system/
- Install the judgehost service:
cp judge/domjudge-judgedaemon@.service /etc/systemd/system/
- You can enable the judgehost on CPU core 1 with:
systemctl enable domjudge-judgedaemon@1
验证安装产物结构:
ls /opt/domjudge
ls /opt/domjudge/domserver/bin /opt/domjudge/judgehost/bin
实测回显:
domserver
judgehost
/opt/domjudge/domserver/bin:
configure-domjudge dj_console dj_setup_database export-contest fix_permissions
force-passwords import-contest
/opt/domjudge/judgehost/bin:
create_cgroups dj_judgehost_cleanup dj_make_chroot
dj_run_chroot judgedaemon runguard runpipe
⚠️ 排障实录:对已安装过的目录重复执行
make install-domserver会在创建dj_console符号链接时报错——实测报错ln: failed to create symbolic link '/opt/domjudge/domserver/bin/dj_console': File exists,随后 make 以 Error 1 结束。这是安装目标不幂等所致:先删除已存在的链接(rm -f /opt/domjudge/domserver/bin/dj_console)再重跑安装即可成功(实测 EXIT=0)。首次安装不会遇到此问题。
4.5 初始化 domserver 数据库
domserver 的数据库初始化由 dj_setup_database 工具完成:先生成凭据文件(genpass),再建库导入默认数据(install)。MariaDB 全新安装后 root 走 unix_socket 认证,必须加 -s 选项让脚本通过本地 socket 连接:
cd /opt/domjudge/domserver
bin/dj_setup_database -s genpass
bin/dj_setup_database -s install
实测回显:
Database credentials read from '/opt/domjudge/domserver/etc/dbpasswords.secret'.
DOMjudge database and user(s) created.
[OK] Already at the latest version ("DoctrineMigrations\Version20250907161952")
> loading App\DataFixtures\DefaultData\ExecutableFixture
> loading App\DataFixtures\DefaultData\LanguageFixture
> loading App\DataFixtures\DefaultData\RoleFixture
> loading App\DataFixtures\DefaultData\TeamCategoryFixture
> loading App\DataFixtures\DefaultData\TeamFixture
> loading App\DataFixtures\DefaultData\UserFixture
> loading App\DataFixtures\ExampleData\JudgehostFixture
初始化完成后,三份关键凭据文件就绪,其中 admin 初始密码存放在 etc/initial_admin_password.secret:
cat etc/dbpasswords.secret
cat etc/initial_admin_password.secret
实测回显(演示环境实测值,生产环境以实际生成为准):
# Randomly generated on host domjudge-lab, Wed Oct 28 05:21:50 UTC 2026
# Format: 'unused:<db_host>:<db_name>:<user>:<password>:<db_port>'
unused:localhost:domjudge:domjudge:oicbAmHBiMGi8YL3:3306
oIvC5NFpXLR9eiiR
💡 说明:
dbpasswords.secret是 domserver 连接 MariaDB 的凭据(格式unused:<db_host>:<db_name>:<user>:<password>:<db_port>),initial_admin_password.secret是 Web 管理员 admin 的初始密码。首次登录后应立即在 Web 界面改掉(本文演示统一改为q1w2e3r4,方法见 4.10 节)。命令行改密工具force-passwords与dj_console domjudge:reset-user-password的行为与排障见本专栏命令篇。
⚠️ 排障实录:不加
-s直接执行会报ERROR 1698 (28000): Access denied for user 'root'@'localhost'——因为 MariaDB 的 root 默认使用 unix_socket 认证插件,而脚本默认尝试以 TCP 方式连接。-s的含义是「connect via local socket (do not specify port)」(脚本自述),在 Ubuntu 22.04 全新 MariaDB 上是必选项。若 MariaDB root 已设置密码,则用-u root -p形式替代。
4.6 配置 nginx 与 PHP-FPM(domserver Web 端)
DOMjudge 官方提供两份生成好的配置:nginx 站点片段与 PHP-FPM 池配置,以符号链接方式接入即可。先把 PHP-FPM 池链接为 8.3 的池配置,再把 nginx 站点配置链接进 sites-enabled:
ln -sf /opt/domjudge/domserver/etc/domjudge-fpm.conf /etc/php/8.3/fpm/pool.d/domjudge.conf
ln -sf /opt/domjudge/domserver/etc/nginx-conf /etc/nginx/sites-enabled/domjudge
两个文件的关键配置(生成自安装模板,默认值即可用):
# /opt/domjudge/domserver/etc/domjudge-fpm.conf(节选)
[domjudge]
user = www-data
group = www-data
listen = /var/run/php-fpm-domjudge.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = static
pm.max_children = 40 ; ~40 per gig of memory(16gb system -> 500)
pm.max_requests = 5000
php_admin_value[memory_limit] = 512M
php_admin_value[upload_max_filesize] = 256M
php_admin_value[post_max_size] = 256M
; This must be strictly larger than the configured max number of source
; files a team can submit.
php_admin_value[max_file_uploads] = 101
逐项说明:listen 是与 nginx 对接的 unix socket(nginx 侧 upstream domjudge 指向它);pm = static + max_children = 40 为固定进程数模型,注释建议按「每 GB 内存 40 个」取值;memory_limit/upload_max_filesize/post_max_size 三个值必须不小于最大测试数据与期望程序输出体积;max_file_uploads = 101 必须大于单次提交允许的源文件数(默认 100)。
重载两个服务使配置生效:
systemctl reload php8.3-fpm
systemctl reload nginx
验证 Web 端已可访问(HTTP 200 且页面标题正常):
curl -s -o /dev/null -w "%{http_code}\n" -L http://localhost/domjudge/
curl -sL http://localhost/domjudge/ | grep -oE "<title>[^<]*</title>" | head -1
实测回显:
200
<title>Scoreboard demo - DOMjudge</title>
💡 说明:nginx 站点配置以
/domjudge/为路径前缀(官方模板默认),所有页面、REST API(/domjudge/api/)都在该前缀下。若要部署在独立域名根路径,编辑/etc/nginx/sites-enabled/domjudge调整prefix与server_name即可。反向代理与真实客户端 IP 传递的进阶配置见本专栏配置篇。
4.7 安装 judgehost(评测机)
judgehost 侧需要四件事:评测运行用户、sudo 授权、REST API 凭据、chroot 沙箱。本节完成前三件。
第一步:创建评测运行用户与组(评测程序以此身份运行,无登录能力):
groupadd -f domjudge-run
useradd -d /nonexistent -g domjudge-run -M -s /bin/false domjudge-run
第二步:部署 sudoers 授权片段(安装时已生成,确认在位即可):
cp /opt/domjudge/judgehost/etc/sudoers-domjudge /etc/sudoers.d/domjudge
chmod 440 /etc/sudoers.d/domjudge
head -10 /etc/sudoers.d/domjudge
实测回显(节选):
# Generated from 'sudoers-domjudge.in' on Wed Oct 28 05:25:54 UTC 2026.
# Example sudoers configuration for DOMjudge judgehosts.
# Check the file paths (especially the chroot prefix),
# give it file mode 0440 and place this file into /etc/sudoers.d/
# (most recent sudo versions; otherwise use an #include statement
# in or add its content to the end of /etc/sudoers)
domjudge ALL=(root) NOPASSWD: /opt/domjudge/judgehost/bin/runguard *
domjudge ALL=(root) NOPASSWD: /bin/chown -R domjudge\: /opt/domjudge/judgehost/judgings/*
要点:规则授权 domjudge 用户免密执行 runguard(评测包装器)与 chroot 挂载相关命令;domjudge 是 judgedaemon 的运行用户(由 configure 的 --with-domjudge-user 决定)。
第三步:配置 REST API 凭据。domserver 安装时已自动创建 judgehost 角色用户,凭据写入两侧的 restapi.secret,两侧必须一致:
cat /opt/domjudge/judgehost/etc/restapi.secret
实测回显(演示环境实测值):
# Randomly generated on host domjudge-lab, Wed Oct 28 05:21:50 UTC 2026
# Format: '<ID> <API url> <user> <password>'
default http://localhost/domjudge/api judgehost 3ClBDfh1CH6By/zXBMANXIAH/lAJho3e
格式为「ID、API 地址、用户名、密码」四列空白分隔。多机部署时把这份文件复制到每台 judgehost 的 etc/restapi.secret,并把 URL 指向 domserver 的实际地址。先用 curl 验证凭据可用:
curl -s -u judgehost:'3ClBDfh1CH6By/zXBMANXIAH/lAJho3e' http://localhost/domjudge/api/v4/judgehosts
实测回显:
[{"id":"1","hostname":"example-judgehost1","enabled":false,"polltime":null,"hidden":false}]
💡 说明:返回里的
example-judgehost1是初始化数据自带的示例条目(disabled 状态),不代表本机 judgehost;本机评测机要在 4.9 节 judgedaemon 首次连接后才会自动注册为新条目。
4.8 构建评测 chroot 沙箱
每个提交程序都在 chroot 沙箱内编译运行,沙箱需要包含编译器与运行时库。dj_make_chroot 用 debootstrap 在 /chroot/domjudge 构建一个与宿主同发行版的完整根文件系统,-i 参数指定额外装入的编译器包:
/opt/domjudge/judgehost/bin/dj_make_chroot -i "gcc,g++,openjdk-11-jdk-headless,python3"
实测回显(输出极长,debootstrap 下载解包数百行,保留首尾关键行,实测首尾):
I: Retrieving InRelease
I: Retrieving Packages
I: Validating Packages
I: Resolving dependencies of required packages...
I: Resolving dependencies of base packages...
...
Replacing debian:TrustAsia_TLS_ECC_Root_CA.pem
Replacing debian:TrustAsia_TLS_RSA_Root_CA.pem
...
Reading package lists...
Building dependency tree...
Reading state information...
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Done building chroot in /chroot/domjudge
验证沙箱就位并可在其中执行命令(dj_run_chroot 不带命令时进入交互 shell,带命令则直接执行):
ls /chroot/domjudge/ | head -8
/opt/domjudge/judgehost/bin/dj_run_chroot gcc --version | head -1
实测回显:
bin dev home lib lib64 media opt root run
srv tmp usr var
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
💡 技术拓展:评测程序的安全隔离手段不止 chroot 一种,主流方案对比——
隔离方案 原理 取舍 chroot(DOMjudge 默认) 切换根文件系统 + runguard 限权 + cgroups 资源限制 依赖宿主 root,启动开销小,判题计时精确 Namespace 隔离 进程/挂载/网络多重隔离 隔离更强,但资源与时间计量精度受共享内核影响 虚拟机沙箱 内核级隔离 隔离最强,启动秒级延迟,判题吞吐低 DOMjudge 9.0 采用「chroot + runguard + cgroups v2」组合,cgroups 还承担网络封锁与多核绑定的职责(judgedaemon
-n参数与 cgroup 一一对应),这也是官方要求内核 ≥ 5.19 的原因。
4.9 systemd 托管(create-cgroups + judgedaemon)
先安装两个官方单元文件:create-cgroups.service(开机创建评测 cgroup)与 domjudge-judgedaemon@.service(模板单元,按核号实例化):
cp /root/domjudge-9.0.1/judge/create-cgroups.service /etc/systemd/system/
cp /root/domjudge-9.0.1/judge/domjudge-judgedaemon@.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now create-cgroups
实测回显:
Synchronizing state of create-cgroups.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable create-cgroups
Created symlink /etc/systemd/system/multi-user.target.wants/create-cgroups.service → /etc/systemd/system/create-cgroups.service.
查看模板单元内容,理解实例化机制:
cat /etc/systemd/system/domjudge-judgedaemon@.service
实测回显(关键段):
[Unit]
Description="DOMjudge judgedaemon bound to CPU #%i"
PartOf=domjudge-judgehost.target
Requires=create-cgroups.service
After=create-cgroups.service
After=network.target
[Service]
Type=simple
ExecStart=/opt/domjudge/judgehost/bin/judgedaemon -n %i
User=domjudge
KillSignal=SIGTERM
TimeoutStopSec=180
FinalKillSignal=SIGKILL
Restart=always
RestartSec=3
PrivateTmp=yes
逐项说明:%i 是实例化占位符(domjudge-judgedaemon@1 实例中取值 1),传给 judgedaemon 的 -n 参数用于绑定 CPU 核;User=domjudge 是 configure 时指定的运行用户;Requires=create-cgroups.service 保证启动前 cgroup 已创建;Restart=always + RestartSec=3 提供故障自动拉起。
启动绑核 1 的评测机实例:
systemctl start domjudge-judgedaemon@1
systemctl is-active domjudge-judgedaemon@1
实测回显:
active
⚠️ 排障实录:若只创建了
domjudge-run用户就启动-n 1实例,服务会陷入重启循环,journalctl -u domjudge-judgedaemon@1实测报错:error: runuser domjudge-run-1 does not exist.。原因是 judgedaemon 以-n <id>绑核运行时,要求存在带核号后缀的运行用户domjudge-run-<id>(官方手册:useradd -d /nonexistent -g domjudge-run -M -s /bin/false domjudge-run-2)。补建对应用户后重启服务即可:
useradd -d /nonexistent -g domjudge-run -M -s /bin/false domjudge-run-1
systemctl restart domjudge-judgedaemon@1
首次连接 domserver 后评测机自动注册。查看启动日志确认 API 轮询建立:
journalctl -u domjudge-judgedaemon@1 --no-pager -n 8 | tail -8
实测回显:
Oct 28 06:23:36 domjudge-lab judgedaemon[49781]: No submissions in queue (for endpoint default), waiting...
Oct 28 06:23:36 domjudge-lab judgedaemon[49781]: No submissions in queue (for endpoint default), waiting...
Oct 28 06:23:36 domjudge-lab judgedaemon[49781]:
Oct 28 06:23:36 domjudge-lab judgedaemon[49781]: API request GET judgehosts
Oct 28 06:23:36 domjudge-lab judgedaemon[49781]:
Oct 28 06:23:37 domjudge-lab judgedaemon[49781]: API request POST judgehosts/fetch-work
Oct 28 06:23:37 domjudge-lab judgedaemon[49781]:
再从 domserver 侧确认注册结果(新增 enabled=true 的本机条目):
curl -s -u judgehost:'3ClBDfh1CH6By/zXBMANXIAH/lAJho3e' http://localhost/domjudge/api/v4/judgehosts | python3 -m json.tool
实测回显:
[
{
"id": "2",
"hostname": "domjudge-lab-1",
"enabled": true,
"polltime": "1793168629.866400000",
"hidden": false
}
]
多核服务器可再启动更多实例(每个实例一个核号与对应用户),例如:
useradd -d /nonexistent -g domjudge-run -M -s /bin/false domjudge-run-2
systemctl start domjudge-judgedaemon@2
4.10 端到端验证:从 Web 登录到自动判题
安装是否成功,最终以「登录 → 建赛 → 提交 → 判题」的完整链路验证。
登录验证:浏览器打开 http://<服务器IP>/domjudge/ 进入公共页,点击右上角登录,用户名 admin,初始密码取自 etc/initial_admin_password.secret(本文实测环境为 oIvC5NFpXLR9eiiR)。登录后立即在「My profile」修改为统一演示口令 q1w2e3r4。命令行方式也可用官方工具改密(需以 root 在 domserver 上执行):
cd /opt/domjudge/domserver
bin/dj_console domjudge:reset-user-password admin q1w2e3r4
实测回显:
[OK] New password for admin is q1w2e3r4
创建比赛与导入题目:安装包自带示例比赛数据(示例比赛 + hello/fltcmp/boolfind 三道题 + 全套判题样例)。若 dj_setup_database install 时已随默认数据一并导入(命令篇有逐条验证),可直接使用;从零导入的方法与 import-contest 用法见命令篇。
提交与判题验证:以团队身份通过 REST API 提交示例题 hello 的 AC 解法(团队用户 demo 的口令同样设为 q1w2e3r4):
curl -s -u demo:q1w2e3r4 -X POST http://localhost/domjudge/api/v4/contests/demo/submissions \
-F "problem_id=hello" -F "language=c" \
-F "code[]=@/opt/domjudge/domserver/example_problems/hello/submissions/accepted/test-hello.c"
实测回显:
{"language_id":"c","time":"2026-10-28T06:26:47.404+00:00","contest_time":"0:56:17.404","team_id":"exteam","problem_id":"hello","files":[],"submitid":1,"id":"1"}
等待判题机拉取(judgedaemon 日志出现 Adding judging run result for jt1 successful. 即完成),查询判题结果:
curl -s -u admin:q1w2e3r4 "http://localhost/domjudge/api/v4/contests/demo/judgements?limit=5" | python3 -m json.tool | head -16
实测回显:
[
{
"start_time": "2026-10-28T06:26:51.595+00:00",
"start_contest_time": "0:56:21.595",
"end_time": "2026-10-28T06:26:53.084+00:00",
"end_contest_time": "0:56:23.084",
"max_run_time": 0.001,
"submission_id": "1",
"id": "1",
"valid": true,
"judgement_type_id": "AC"
}
]
判题在约 1.5 秒内完成(编译 + 运行 + 比对),结果 AC,说明「Web 提交 → judgedaemon 拉取 → chroot 编译运行 → 结果回写」全链路通畅。至此方案 A 安装完毕。
五、离线安装方案 B(tarball 离线编译)
5.1 方案说明
方案 B 面向无外网(或弱外网)的赛事内网服务器:依赖包与源码 tarball 全部由有网机器预先取得并转入内网,服务器在离线状态下完成与方案 A 完全一致的编译安装流程。与方案 A 的差异只在「依赖与源码的获取渠道」,编译、数据库、Web、评测机、沙箱各步骤完全相同,本章只展开有差异的部分。
5.2 离线依赖准备
在有网机器上用 apt-get download(或 apt-get install --download-only)拉取方案 A 4.2 节的全部依赖包及其依赖闭包,连同 ppa:ondrej/php 的 PHP 8.3 系列一起转入内网:
mkdir -p debs && cd debs
apt-get download build-essential make gcc g++ autoconf automake \
composer php8.3-cli php8.3-mysql php8.3-zip php8.3-gd php8.3-curl \
php8.3-intl php8.3-mbstring php8.3-xml php8.3-fpm php8.3-ds php8.3-bcmath \
nginx mariadb-server acl sudo debootstrap lsof procps
预期结果:目录内生成全部 .deb 文件(依赖闭包建议配合 apt-cache depends --recurse 核对,或直接在一台同版本机器上用 apt-get install --download-only -y 一次拉全)。将 debs/ 目录与官方 tarball(方案 A 4.3 节同一 URL 的 domjudge-9.0.1.tar.gz)一并拷贝到内网服务器。
⚠️ 注意:ppa:ondrej/php 的包在离线机上安装时可能提示依赖缺失(如
php8.3-common的版本锚定),务必在有网机器上以完全相同的 Ubuntu 版本执行下载,并用apt-get install -y --no-install-recommends ./debs/*.deb在内网机本地安装。
5.3 离线编译安装与初始化
内网机安装本地 deb 并解压源码:
apt-get install -y /path/to/debs/*.deb
tar xzf /path/to/domjudge-9.0.1.tar.gz -C /root
之后的步骤与方案 A 完全一致(configure 参数、make 目标、dj_setup_database、nginx/fpm 链接、judgedaemon 单元均相同),唯二注意点:
- chroot 构建的 debootstrap 需要基础包源:
dj_make_chroot会在线拉取 Ubuntu 基础包。内网机需配置可访问的 Ubuntu 软件源(--mirror参数指定内网源地址),例如/opt/domjudge/judgehost/bin/dj_make_chroot -i "gcc,g++,openjdk-11-jdk-headless,python3" --mirror http://<内网源>/ubuntu;或在有网机器上构建好/chroot/domjudge后整目录打包拷贝过来(实测同架构同发行版可直接使用)。 - 版本校验:内网转入的 tarball 建议同时携带官方站的 sha256 校验值核对,防止传输损坏。
5.4 验证
离线安装的验证方法与方案 A 4.10 节完全一致:Web 登录、judgehost 注册、示例提交 AC 判题三项全部通过即视为安装成功。本文方案 A 的全部实测回显对方案 B 同样成立(两方案产物与流程相同)。
六、方案对比与选择建议
| 维度 | 方案 A:在线 tarball 编译 | 方案 B:离线 tarball 编译 |
|---|---|---|
| 版本 | 官方 9.0.1(与官网一致) | 同左(tarball 转入) |
| 是否需联网 | 编译期需联网下载依赖与源码 | 编译期完全离线 |
| 依赖来源 | Ubuntu 源 + ppa:ondrej/php | 有网机预下载 deb 转入 |
| chroot 构建 | debootstrap 在线拉取 | 需内网源或异地构建拷入 |
| 安装方式 | 源码编译(configure/make) | 源码编译(同左) |
| systemd 服务名 | create-cgroups + domjudge-judgedaemon@N | 同左 |
| 优缺点 | 步骤最少、版本最新;依赖外网稳定 | 内网可控;依赖准备环节易踩版本锚定坑 |
选择建议:可联网服务器一律选方案 A(官方主线、步骤最少);赛场内网、保密内网或外网不稳定的部署场景选方案 B,并提前在有网环境完整演练一遍依赖下载(特别是 PHP 8.3 PPA 的依赖闭包)。两方案产物一致,后续运维、配置、升级方法通用。
七、配置说明
安装完成后,日常会打交道的配置文件族集中在 /opt/domjudge 与 /etc 两处。本节给出生效位置与关键项速查,逐项参数详解见本专栏配置篇。
| 文件 | 作用 | 关键内容 |
|---|---|---|
/opt/domjudge/domserver/etc/dbpasswords.secret | domserver 连 MariaDB 凭据 | 主机/库名/用户/密码/端口 |
/opt/domjudge/domserver/etc/initial_admin_password.secret | admin 初始密码 | 首登后立即改密 |
/opt/domjudge/domserver/etc/domserver-static.php | 安装期生成的静态定义 | 版本号、安装路径、BASEURL |
/opt/domjudge/domserver/etc/nginx-conf(+inner) | nginx 站点片段 | /domjudge/ 前缀、API 路由、fpm socket |
/opt/domjudge/domserver/etc/domjudge-fpm.conf | PHP-FPM 池 | memory_limit 512M、上传 256M |
/opt/domjudge/judgehost/etc/restapi.secret | 评测机对接 domserver 凭据 | ID/URL/用户/密码 四列 |
/opt/domjudge/judgehost/etc/judgehost-config.php | 评测机行为配置 | syslog、可写临时目录、HTTP 退避参数 |
/opt/domjudge/judgehost/etc/sudoers-domjudge | 评测机 sudo 规则 | runguard、chroot 挂载免密 |
/chroot/domjudge | 评测沙箱根文件系统 | 编译器与运行时 |
/etc/systemd/system/domjudge-judgedaemon@.service | 评测机 systemd 模板单元 | -n %i 绑核、User=domjudge |
Web 层业务参数(判题内存上限、罚时、榜单显示等)不在文件中,存于数据库 configuration 表,通过 admin 界面 Settings 修改——这部分逐项验证与修改方法见配置篇。
配置修改后的通用验证方法:改 nginx/fpm 配置后 systemctl reload nginx 与 systemctl reload php8.3-fpm 并以 curl -o /dev/null -w "%{http_code}" http://localhost/domjudge/ 确认 200;改 judgedaemon 相关配置后 systemctl restart domjudge-judgedaemon@1 并确认 systemctl is-active 返回 active。
八、常见问题(FAQ)
Q1:configure 报「installing/running as root is STRONGLY DISCOURAGED」怎么办?
先创建普通用户(useradd -m domjudge)并加 --with-domjudge-user=domjudge 重新 configure。这是官方硬约束:评测运行用户不能是 root(详见 4.4 节排障实录)。
Q2:Ubuntu 22.04 源里的 PHP 8.1 能直接用吗? 不能。9.0 系列要求 PHP ≥ 8.2.0,必须经 ppa:ondrej/php 安装 php8.3 全家桶(含官方点名的 ds、bcmath 扩展),否则 domserver 运行异常(详见 4.2 节排障实录)。
Q3:dj_setup_database 报 ERROR 1698 Access denied for root?
MariaDB root 默认 unix_socket 认证,脚本默认 TCP 连接。加 -s 选项走本地 socket 即可;若 root 设有密码则用 -u root -p(详见 4.5 节排障实录)。
Q4:judgedaemon 一直 restarting,日志报 runuser domjudge-run-1 does not exist?
-n <id> 绑核实例要求对应用户 domjudge-run-<id>。逐个补建(每核一个用户)后 systemctl restart domjudge-judgedaemon@<id>(详见 4.9 节排障实录)。
Q5:重新执行 dj_setup_database genpass/install 后 Web 全站 500?
genpass 会重写 dbpasswords.secret/restapi.secret/initial_admin_password.secret 为新随机值,但已存在的数据库用户与 Web 用户密码不会自动跟随,导致 domserver 连库、评测机连 API 全部失配。修复顺序:dj_setup_database -s update-password(把数据库用户密码同步为 secret 新值)→ force-passwords(把 judgehost API 用户与 admin 重置为 secret/初始密码文件的值)→ 用 dj_console domjudge:reset-user-password 恢复自定义口令。本文实测中该链路完整恢复(详见 4.5 节提示与命令篇)。
Q6:直连 domjudge.org 下载极慢或超时? 实测直连约 100–170KB/s 且中途截断,代理(http://192.168.1.62:7897)约 3.8MB/s 稳定完整。按「官方源 → 国内源 → 代理」降级链选择,tarball 也可从有网机器转入(离线场景见方案 B)。
Q7:judgehost 提交后一直 pending 不判题?
依次检查:systemctl is-active domjudge-judgedaemon@1 是否 active;judgedaemon 日志有无 API 连接错误(restapi.secret 是否与 domserver 侧一致);Web 端 admin → Judgehosts 中本机是否 enabled;chroot 是否构建成功(ls /chroot/domjudge)。
Q8:如何加第二台评测机?
新机器上只装 judgehost 角色(4.4 节的 judgehost 构建目标 + 4.7/4.8/4.9 节),把 domserver 的 restapi.secret 复制过去并把 URL 指向 domserver 地址,启动 judgedaemon 后自动注册。判题机扩容是增量操作,无需动 domserver。
九、卸载与清理
卸载按「评测机 → 数据库 → 安装目录 → Web 配置」顺序回退,每步可独立执行。
# 1. 停止并移除评测机与 cgroup 服务
systemctl disable --now domjudge-judgedaemon@1
systemctl disable --now create-cgroups
rm -f /etc/systemd/system/domjudge-judgedaemon@.service /etc/systemd/system/create-cgroups.service
systemctl daemon-reload
# 2. 删除数据库与数据库用户(不可恢复,先备份!)
/opt/domjudge/domserver/bin/dj_setup_database -s uninstall
uninstall 的官方自述为「remove database users and database, INCLUDING ALL DATA!」,执行前务必用 mysqldump --max_allowed_packet=1G --single-transaction domjudge > domjudge-backup.sql 备份(实测提醒:不加 --max_allowed_packet 会在导出大测试用例表时中断,详见命令篇排障实录)。
# 3. 移除安装目录与沙箱
rm -rf /opt/domjudge /chroot/domjudge
# 4. 移除 Web 侧配置并还原服务
rm -f /etc/nginx/sites-enabled/domjudge /etc/php/8.3/fpm/pool.d/domjudge.conf
rm -f /etc/sudoers.d/domjudge
systemctl reload php8.3-fpm && systemctl reload nginx
验证清理彻底:ls /opt/domjudge /chroot/domjudge 应报 No such file or directory;mysql -e "show databases" 中无 domjudge 库;curl -o /dev/null -w "%{http_code}" http://localhost/domjudge/ 不再返回 200。
十、参考链接
- 官方下载页(版本与 tarball):https://www.domjudge.org/download
- 官方管理员手册 Installation of the DOMserver:https://www.domjudge.org/docs/manual/main/install-domserver.html
- 官方管理员手册 Installation of the judgehosts:https://www.domjudge.org/docs/manual/main/install-judgehost.html
- 官方关于页(系统要求):https://www.domjudge.org/about
- 开发仓库(Release 与 Issue):https://github.com/domjudge/domjudge
- 站内相关:《DOMJudge 介绍与选型指南》(架构与选型背景)、《DOCAT Ubuntu 22.04 安装部署指南(nginx + systemd 实测)》(同为 nginx + systemd 托管的 Ubuntu 安装范式)、《DOCAT 配置参数详解(环境变量 / nginx 反代 / 认证实测)》(nginx 反代与认证配置思路参照)