Building a programming contest system with Domjudge on LAMP & AWS

Oct 26, 2017

Competitive programming is increasingly popular largely due to the soaring demand of software engineers and ‘coding interviews’ as a rite of passage for becoming one. A number of services have emerged to provide contest systems along with computing resources and problemsets. However, one may find that such proprietary systems are not without their limits. Domjudge is an open source platform to host programming contests. It comes with an automated judging system to run programming contests, as well as interfaces for participants (called teams) to submit their solution code ahd receive the verdict. The administrator can coordinate multiple contests simulatneously and appoint juries to oversee each contest. It supports an ACM-ICPC format and is widely adopted by ICPC regional directors and university contests.


Here we introduce how to set up an environment with LAMP. Please consult the official documentation for other settings. We employed AWS but you may build on-premises following this instruction, except that you need to do networking parts on your own.

We used Domjudge 5.3.0 here, which may well become outdated some day, and advise to use a recent but stable version for the contests.


0. Pre-requisites

You could put all of the above in a single instance, but it is highly discouraged. First, the Judgehosts require an exclusive usage of CPU during execution. Even though they consider the user execution time when judging the solutions, instead of the real execution time, the execution time of a submission might considerably differ due to cache misses or I/O interrupts. It makes jury onerous to set a tight time limit. (e.g. O(Nlg^2N) should be rejected but not O(NlgN)) Also, it is recommended to use an isolated database for security reasons, especially when you can’t rule out malicious submissions from untrusted users. For brevity, however, we will put the database into the main server in this post.

1. Install the Main Server


$ sudo apt update
$ sudo apt install -y gcc g++ make zip unzip php-fpm php-cli php-gd php-curl php-mbstring php-mysql php-json php-xml php-mcrypt php-zip bsdmainutils ntp linuxdoc-tools linuxdoc-tools-text groff texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended apache2 mysql-client mysql-server libapache2-mod-php libcgroup-dev

It will take several minutes. You may not install mysql-server if you decided to use the external database server. Remember the password of mysql for later.

Download & Build

$ wget
$ tar -xzf domjudge-5.3.0.tar.gz
$ cd domjudge-5.3.0
$ ./configure --disable-submitclient
$ make domserver && make docs
$ sudo make install-domserver && sudo make install-docs 

Now you have domserver installed at /opt/domjudge/domserver.

Configure Database Setting

$ sudo vi /opt/domjudge/domserver/etc/dbpasswords.secret

# Randomly generated on host ip-*-*-*-*, Thu Oct 26 12:03:44 UTC 2017
# Format: 'dummy:<db_host>:<db_name>:<user>:<password>'

Setup Database

$ cd /opt/domjudge/domserver/bin

/* You need to change the host if you have decided to use external DB server. Otherwise, skip this. */
$ vi ./dj_setup_database
/* Replace 'localhost' to your designated server. */
$ ./dj_setup_database -u root -r bare-install
Database credentials read from '/opt/domjudge/domserver/etc/dbpasswords.secret'.
Enter password: _[Your Database User password]_
DOMjudge database and user(s) created.
Enter password: _[Your Database User password]_
SQL structure and defaults installed (no sample data).

Apache2 Configuration

Domjudge provides .conf file for apache2, which is located at etc/apache.conf.

$ sudo ln -s ~/domjudge-5.3.0/etc/apache.conf /etc/apache2/conf-available/domjudge.conf
$ sudo a2enconf domjudge
$ sudo service apache2 reload

Now you can use the web interface at your.server.address/domjudge/.

Login as an administrator with admin/admin. In the user tab, you will see the judgehost in the list. Set the password and remember it. It will be later used for setting up the judgehosts.

Config Checker

In the home tab, click the “Config checker” below the ‘Administrator’ section. The following is the screenshot if you’ve come through right. When clicking each tab, it will show you how to fix the involving issue. Do as it suggests. “Active contests” is okay for this moment.

2. Install Judgehosts

Install Dependencies

$ sudo apt install gcc g++ make cmake zip unzip debootstrap php-cli php-zip php-curl php-json procps openjdk-8-jre-headless openjdk-8-jdk libcgroup-dev -y

It will take a while.

Enable cgroups

$ sudo vi /etc/default/grub.d/50-cloudimg-settings.cfg 

/* In line 11 (probably), append the following */
GRUB_CMDLINE_LINUX_DEFAULT="~~~~ quiet cgroup_enable=memory swapaccount=1”

$ sudo update-grub
$ sudo reboot

This will allow domjudge to use cgroups library. If you’re using your own machines (not AWS), modify /etc/default/grub instead of /etc/default/grub.d/50-cloudimg-settings.cfg.

After the reboot, check if you can see a message like this:

$ cat /proc/cmdline 
BOOT_IMAGE=/boot/vmlinuz-4.4.0-1022-aws root=UUID=*-*-*-* ro console=tty1 console=ttyS0 quiet cgroup_enable=memory swapaccount=1

Download & Build

$ wget
$ tar -xzf domjudge-5.3.0.tar.gz

$ sudo ./configure --enable-cgroups --disable-submitclient --with-domjudge-user=root
$ sudo make domserver && sudo make judgehost
$ sudo make install-judgehost

Now we have a binary at /opt/domjudge/judgehost. If you want to use multiple judgehosts, repeat above for each judgehost.

Connect with the Main Server

$ sudo vi /opt/domjudge/judgehost/etc/restapi.secret

# Randomly generated on host ip-*-*-*-*, Thu Oct 26 12:59:58 UTC 2017
# Format: '<ID> <API url> <user> <password>'
default http://_[Your Main Server}_/domjudge/api judgehost _[Your judgehost Password]_

For security issues, the domjudge recommends using chroot. You may skip this part if you trust users.

$ sudo vi /opt/domjudge/judgehost/bin/dj_make_chroot

/* Line 30-31 */

/* Line 103 */
INSTALLDEBS="openjdk-8-jre-headless locales"

/* Line 132 */
INSTALLDEBS="openjdk-8-jre-headless locales"

$ sudo /opt/domjudge/judgehost/bin/dj_make_chroot

It will take several minutes depending on the server’s status. After completing, add a user and start the daemon:

$ sudo useradd -d /nonexistent -g nogroup -s /bin/false domjudge-run
$ cd /opt/domjudge/judgehost
$ sudo bin/judgedaemon

If you can see the judgehost list in the web interface, everything is done! Be sure to keep your session open during the judging. (Use tmux or the like)

3. Stress Test

You may want to check how much judging requests the hosts can handle in advance. For that, please see Bear in mind that each submission will cost 100% of CPU for X times of the time limit plus domjudge overhead. Empirically, we found the following settings worked well.

# of Teams # of Instances for Judgehosts Disk Space (GB)
10 2 8
50 4 10
100 6 16
500 18 32

However, contestants tend to storm submissions at the later stage of the contest. It will be needed to scale out about 1.5x-3x to deliver quick verdicts throughout the contest. Prepare extra instances in advance if need be. Use non-preemptible instances.

Also, be sure to supply enough disk space. If the correct output is 500,000 32-bit integers, each will eat up several MBs in the disk.

4. Spotboard

Spotboard is a modern-style, web-based scoreboard application for programming contests, notably ACM-ICPC. It has been officially used in the ACM-ICPC Regional of South Korea since 2015. Please follow the link to couple it with Domjudge.