A production-ready command-line tool for managing DOMjudge infrastructure and programming contests. Deploy, configure, and manage competitive programming platforms with Infrastructure-as-Code principles.
- Installation
- Quick Start
- Important: Tool Scope
- Command Reference
- Configuration
- Usage Examples
- Troubleshooting
- Python: 3.10 or higher
- Docker: Required for running DOMjudge infrastructure
- Operating System: Linux (Ubuntu 22.04 recommended), macOS
Enable cgroups for judgehost functionality:
Ubuntu 22.04:
-
Create GRUB configuration:
sudo vi /etc/default/grub.d/99-domjudge-cgroups.cfg
-
Add this line:
GRUB_CMDLINE_LINUX_DEFAULT="cgroup_enable=memory swapaccount=1 systemd.unified_cgroup_hierarchy=0" -
Update and reboot:
sudo update-grub sudo reboot
-
Verify:
cat /proc/cmdline # Should show cgroup settings
pip install domjudge-cli
dom --version# 1. Initialize configuration
dom init
# 2. Deploy infrastructure
dom infra apply
# 3. Create contests with problems and teams
dom contest applyAccess DOMjudge at http://localhost:8080 (or configured port).
This tool is designed for INITIAL SETUP of DOMjudge infrastructure and contests.
- Deploy DOMjudge infrastructure (Docker containers)
- Create new contests with problems and teams
- Plan changes before applying them
- Scale judgehost count
- ❌ Update existing contests (DOMjudge API limitation)
- ❌ Update team/problem data after creation
- ❌ Ongoing contest management (use DOMjudge web UI instead)
Example:
# ✓ Initial setup - Works perfectly
dom init
dom infra apply
dom contest apply
# ❌ Updating existing contest - NOT supported
vim dom-judge.yaml # Change contest duration
dom contest apply # ⚠ Warning: Update manually in web UIFor ongoing management, use the DOMjudge web interface.
All commands support:
| Option | Description |
|---|---|
--verbose |
Enable detailed logging |
--no-color |
Disable colored output |
--version, -v |
Show version |
--help |
Show help |
Example:
dom --verbose infra statusInitialize DOMjudge configuration file.
dom init [OPTIONS]| Option | Description |
|---|---|
--overwrite |
Overwrite existing configuration |
--dry-run |
Preview without creating files |
Launches an interactive wizard to create dom-judge.yaml with:
- Infrastructure settings (port, judges)
- Contest details
- Problems and teams
Examples:
# Basic initialization
dom init
# Preview what would be created
dom init --dry-run
# Overwrite existing config
dom init --overwriteManage DOMjudge infrastructure.
dom infra apply- Deploy infrastructuredom infra plan- Preview infrastructure changesdom infra status- Check infrastructure healthdom infra destroy- Remove infrastructure
Deploy or update infrastructure from configuration.
dom infra apply [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
--dry-run |
Preview without applying |
Usage:
Deploys Docker containers for:
- DOMserver (web interface + API)
- MariaDB database
- Judgehosts (configurable count)
- MySQL client
Examples:
# Deploy with default config
dom infra apply
# Use custom config file
dom infra apply -f my-config.yaml
# Preview deployment
dom infra apply --dry-run
# Deploy with verbose logging
dom infra apply --verboseAccess: After deployment, DOMjudge is available at configured port (default: http://localhost:8080)
Show infrastructure changes before applying.
dom infra plan [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
Usage:
Analyzes configuration and displays:
- Whether infrastructure needs creation or updates
- Safe changes (e.g., scaling judges) vs. changes requiring restart
- Current vs. desired state comparison
Examples:
# Preview infrastructure changes
dom infra plan
# Use custom config
dom infra plan -f my-config.yamlOutput shows:
- Port changes (requires restart)
- Judge count changes (safe live update)
- Password changes (requires restart)
Check infrastructure health.
dom infra status [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file for expected state |
--json |
Output as JSON |
Usage:
Checks status of:
- Docker daemon
- DOMserver container
- MariaDB database
- Judgehost containers
- MySQL client
- Network connectivity
Examples:
# Check status
dom infra status
# Check against expected config
dom infra status -f dom-judge.yaml
# JSON output for scripts
dom infra status --jsonExit codes:
0- All healthy1- Issues detected
Remove all infrastructure.
dom infra destroy [OPTIONS]Options:
| Option | Description |
|---|---|
--confirm |
Required - Confirm destruction |
--force-delete-volumes |
Delete data volumes (PERMANENT) |
--dry-run |
Preview without destroying |
Usage:
Stops and removes containers. By default, preserves volumes (contest data, submissions, database).
Examples:
# Remove infrastructure (keep data)
dom infra destroy --confirm
# Complete removal (DATA LOSS)
dom infra destroy --confirm --force-delete-volumes
# Preview what would be removed
dom infra destroy --dry-runSafety: Requires --confirm flag to prevent accidents.
Manage contests, problems, and teams.
dom contest apply- Create contestsdom contest plan- Preview contest changesdom contest verify-problemset- Verify problemsdom contest inspect- Inspect configuration
Create contests with problems and teams.
dom contest apply [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
--dry-run |
Preview without applying |
Usage:
Creates or updates:
- Contests
- Problem packages
- Teams and affiliations
- Contest settings
Important: Cannot update existing contest fields (API limitation). For changes after creation, use DOMjudge web UI.
Examples:
# Create contests from config
dom contest apply
# Use custom config
dom contest apply -f my-contest.yaml
# Preview changes
dom contest apply --dry-run
# Verbose output
dom contest apply --verboseShow contest changes before applying.
dom contest plan [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
Usage:
Analyzes configuration and displays:
- Contests to be created
- Field changes detected (with warnings if not updatable)
- Problems/teams to be added
- Current vs. desired state
Examples:
# Preview contest changes
dom contest plan
# Use custom config
dom contest plan -f my-config.yamlOutput shows:
- New contests to create
- Existing contests and detected changes
- Problems/teams to add
- Warnings for unsupported updates
Verify problems by running test submissions.
dom contest verify-problemset CONTEST_NAME [OPTIONS]Arguments:
| Argument | Description |
|---|---|
CONTEST_NAME |
Contest name or shortname |
Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
--dry-run |
Preview without running |
Usage:
Validates problems by:
- Running sample submissions
- Checking expected results
- Verifying performance limits
- Reporting successes/failures
Examples:
# Verify contest problemset
dom contest verify-problemset "ICPC Regional 2025"
# Use shortname
dom contest verify-problemset SAMPLE2025
# With custom config
dom contest verify-problemset SAMPLE2025 -f config.yaml
# Preview what would be verified
dom contest verify-problemset SAMPLE2025 --dry-runExit codes:
0- All problems verified1- Verification failed
Inspect loaded configuration.
dom contest inspect [OPTIONS]Options:
| Option | Description |
|---|---|
-f, --file PATH |
Config file (default: dom-judge.yaml) |
--format EXPR |
JMESPath expression for filtering |
--show-secrets |
Show secret values (default: masked) |
Usage:
Displays parsed configuration with validation.
Examples:
# Inspect configuration
dom contest inspect
# Show with secrets
dom contest inspect --show-secrets
# Filter specific data
dom contest inspect --format "contests[0].name"
# Use custom config
dom contest inspect -f my-config.yamlConfiguration is defined in dom-judge.yaml (created by dom init).
infra:
port: 8080
judges: 4
password: "your-secure-password"
contests:
- name: "ICPC Regional 2025"
shortname: "ICPC2025"
duration: "5:00:00"
problems:
- archive: "problems/hello/"
platform: "domjudge"
color: "blue"
- archive: "problems/fizzbuzz.zip"
platform: "domjudge"
color: "red"
- archive: "problems/polygon-problem-linux.zip"
platform: "polygon"
color: "green"
with_statement: true
teams:
- name: "Team Alpha"
affiliation: "University A"
country: "USA"
- name: "Team Beta"
affiliation: "University B"
country: "CAN"| Field | Type | Description |
|---|---|---|
port |
integer | DOMjudge web port (1024-65535) |
judges |
integer | Number of judgehost containers |
password |
string | Admin password (8-128 chars) |
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Contest display name |
shortname |
string | Yes | Short identifier (3-32 chars) |
duration |
string | Yes | Format: H:MM:SS |
formal_name |
string | No | Official name |
start_time |
datetime | No | ISO 8601 format |
penalty_time |
integer | No | Minutes per wrong submission |
problems |
list | Yes | Problem packages |
teams |
list | Yes | Team registrations |
The tool supports two problem formats:
- DOMjudge/Kattis Problem Package Format (recommended)
- Polygon Format (automatically converted to DOMjudge format)
| Field | Type | Required | Description |
|---|---|---|---|
archive |
string | Yes | Path to problem archive (.zip) or directory |
platform |
string | Yes | "domjudge" or "polygon" |
color |
string | Yes | Problem color (hex code or name) |
with_statement |
boolean | No | Include problem statement (Polygon only, default: true) |
DOMjudge/Kattis Format - Required files:
problem.yaml- Problem metadatadomjudge-problem.ini- DOMjudge settingsdata/sample/*.in- Sample inputsdata/sample/*.ans- Sample outputsdata/secret/*.in- Test casesdata/secret/*.ans- Expected outputs
Polygon Format:
.ziparchive from Codeforces Polygon- Important: Export as Linux package (not Standard or Windows)
- Automatically converted to DOMjudge format during import
Example configuration:
problems:
# DOMjudge format (directory)
- archive: "problems/hello/"
platform: "domjudge"
color: "#FF5733"
# DOMjudge format (zip)
- archive: "problems/fizzbuzz.zip"
platform: "domjudge"
color: "blue"
# Polygon format (must be Linux package!)
- archive: "problems/polygon-problem-linux.zip"
platform: "polygon"
color: "green"
with_statement: trueThe tool supports multiple ways to specify problem configurations:
1. Inline problems (as shown above)
contests:
- name: "Contest 1"
problems:
- archive: "problems/hello/"
platform: "domjudge"
color: "blue"2. External problems file
contests:
- name: "Contest 1"
problems:
from: "problems.yaml" # or problems.ymlThen create problems.yaml:
- archive: "problems/hello/"
platform: "domjudge"
color: "blue"
- archive: "problems/fizzbuzz.zip"
platform: "domjudge"
color: "red"3. Problems from a directory
contests:
- name: "Contest 1"
problems:
from: "contest1-problems/"The tool will look for contest1-problems/problems.yaml or contest1-problems/problems.yml.
4. Default problems lookup
contests:
- name: "Contest 1"
problems: {} # Empty object triggers default lookupThe tool will automatically look for problems.yaml or problems.yml in the same directory as dom-judge.yaml.
This pattern is useful when:
- You want to keep your main config file clean and focused
- Multiple contests share the same problem set
- You're managing a large problem set separately
Teams can be defined in two ways: inline YAML or CSV file import.
Define teams directly in your configuration file:
teams:
- name: "Team Alpha"
affiliation: "University A"
country: "USA"
- name: "Team Beta"
affiliation: "University B"
country: "CAN"Fields:
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Team display name |
affiliation |
string | Yes | Organization name |
country |
string | No | 3-letter code (USA, CAN, etc.) |
For contests with many teams, import from CSV files:
teams:
from: "teams.csv"
delimiter: ","
rows: "2-50"
name: "$2"
affiliation: "$3"
country: "$4"Configuration Fields:
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | Yes | Path to CSV/TSV file |
delimiter |
string | No | Field separator (, for CSV, \t for TSV) |
rows |
string | Yes | Row range to import (e.g., "2-50") |
name |
string | Yes | Column mapping for team name (e.g., "$2") |
affiliation |
string | Yes | Column mapping for affiliation (e.g., "$3") |
country |
string | No | Column mapping for country code (e.g., "$4") |
Interactive Column Mapping:
When you run dom init, you'll:
- Select your teams CSV file
- See a preview of the first few rows with column numbers
- Choose which columns map to name, affiliation, and country
- Confirm or adjust the detected row range
This ensures flexibility regardless of your CSV structure.
CSV File Best Practices:
- Include clear headers in the first row (excluded from import)
- Use UTF-8 encoding to support international characters
- Keep consistent formatting across all rows
- Include all required fields: name, affiliation, country
Example CSV: teams.csv
id,name,affiliation,country
1,Team Alpha,University A,USA
2,Team Beta,University B,CAN
3,Team Gamma,College C,FRA
4,Team Delta,Institute D,DEU
5,Team Epsilon,Academy E,GBRAlternative CSV (different column order):
team_name,country_code,university,team_id
Alpha Warriors,USA,MIT,T001
Beta Coders,CAN,UBC,T002
Gamma Hackers,FRA,ENS,T003During dom init, you'll map:
- Column 1 (
team_name) → name:"$1" - Column 3 (
university) → affiliation:"$3" - Column 2 (
country_code) → country:"$2"
Country Codes:
Use ISO 3166-1 alpha-3 country codes. Common examples:
| Code | Country |
|---|---|
| USA | United States |
| CAN | Canada |
| DEU | Germany |
| GBR | United Kingdom |
| JPN | Japan |
| MAR | Morocco |
Row Range Specification:
The rows field defines which rows contain team data:
- Format:
"start-end"(1-indexed, inclusive) - Example:
"2-50"imports rows 2 through 50 - Row 1 is typically headers (excluded)
- During
dom init, the tool auto-detects the range based on file size
TSV Format Support:
For tab-separated files, use .tsv extension:
teams:
from: "teams.tsv"
delimiter: "\t" # Tab character
rows: "2-100"
name: "$1"
affiliation: "$2"
country: "$3"Complete Example:
contests:
- name: "ICPC Regional 2025"
shortname: "ICPC2025"
duration: "5:00:00"
problems:
from: "problems.yaml"
teams:
from: "teams.csv"
delimiter: ","
rows: "2-45"
name: "$2"
affiliation: "$3"
country: "$4"# 1. Create configuration
dom init
# 2. Review infrastructure plan
dom infra plan
# 3. Deploy infrastructure
dom infra apply
# 4. Verify deployment
dom infra status
# 5. Review contest plan
dom contest plan
# 6. Create contests
dom contest apply
# 7. Verify problems
dom contest verify-problemset "My Contest"# Edit config to change judge count
vim dom-judge.yaml # Change judges: 4 -> 8
# Preview changes
dom infra plan # Shows: Safe judge scaling
# Apply changes (no downtime)
dom infra apply# Remove infrastructure (keep data)
dom infra destroy --confirm
# Complete removal including data
dom infra destroy --confirm --force-delete-volumes#!/bin/bash
# Check if DOMjudge is healthy
if dom infra status --json > /dev/null 2>&1; then
echo "✓ DOMjudge is healthy"
exit 0
else
echo "✗ DOMjudge has issues"
exit 1
fi# Production
dom infra apply -f production.yaml
dom contest apply -f production.yaml
# Staging
dom infra apply -f staging.yaml
dom contest apply -f staging.yamlProblem: Containers won't start
# Check Docker daemon
docker ps
# Check logs
docker logs domjudge-cli-domserver
# Verify cgroups (Linux)
cat /proc/cmdlineProblem: Port already in use
# Change port in config
vim dom-judge.yaml # Change port: 8080 -> 9090
# Destroy and redeploy
dom infra destroy --confirm
dom infra applyProblem: Judgehosts not running
# Check status
dom infra status
# View logs
docker logs domjudge-cli-judgehost-1
# Verify cgroups configurationProblem: Problems fail to upload
# Verify problem package format
# Must have problem.yaml and data/ directory
# Check logs
dom contest apply --verboseProblem: Team creation fails
# Check team data format
# Name, affiliation, country required
# Use verbose mode
dom contest apply --verboseProblem: "Contest already exists" warning
This is expected when trying to update contest fields. The tool can only CREATE contests, not update them. Use DOMjudge web UI for updates.
Problem: Configuration validation fails
# Inspect parsed config
dom contest inspect
# Check YAML syntax
# Ensure proper indentation and structureProblem: Docker permission denied
# Add user to docker group (Linux)
sudo usermod -aG docker $USER
newgrp docker- Use version control for configuration files
- Test with
--dry-runbefore applying changes - Use
plancommands to preview changes - Keep credentials secure - use environment variables or secrets manager
- Back up volumes before using
--force-delete-volumes - Monitor with
infra statusin production - Use DOMjudge web UI for contest management after initial setup
- Documentation: https://github.com/AnasImloul/domjudge-cli
- Issues: https://github.com/AnasImloul/domjudge-cli/issues
- DOMjudge: https://www.domjudge.org/
- Kattis Problem Format: https://www.kattis.com/problem-package-format/
Built with ❤️ for the competitive programming community.