hzxie
voj
Java

A cross-platform online judge system based on Spring framework and ActiveMQ.

Last updated Jun 30, 2026
611
Stars
120
Forks
0
Issues
0
Stars/day
Attention Score
88
Language breakdown
No language data available.
Files click to expand
README

Verwandlung Online Judge

CircleCI Build status codecov Docker Pulls License: GPL v3

Official Demo · Project Page · Change Log

Introduction

Verwandlung Online Judge is a self-hostable, open-source online judge for competitive programming. It presents algorithmic problems, accepts submissions in multiple languages, then compiles, runs and evaluates them against predefined test cases, reporting correctness, run time and memory usage.

Highlights:

  • Cross-platform native judging. Submissions are judged natively on Linux
and Windows through JNI, rather than relying on a Linux-only runtime.
  • Sandboxed execution. On Linux each submission runs under kernel-enforced
resource limits, a private network namespace and a seccomp syscall filter, as an unprivileged user; on Windows it runs under a separate low-privilege account inside a Job Object that caps the process count and enforces resource limits.
  • Real-time feedback streamed to the browser with Server-Sent Events (SSE), so
results appear progressively as each test case finishes.
  • Horizontally scalable judging. The web app and the judgers are decoupled
through an Apache ActiveMQ queue, so you can run as many judgers in parallel as you need.
  • Contests and internationalization (English and Chinese) out of the box.
It is built on Spring Boot with the MyBatis persistence framework.

Architecture

Verwandlung has two components, the web application and one or more judgers, communicating over ActiveMQ:

Software Architecture

Getting Started

Run with Docker (recommended)

The fastest way to stand up the whole stack (database, message queue, web app and a judger) — two equivalent options:

git clone https://github.com/hzxie/voj.git
cd voj

A) Docker Compose

docker compose up -d

B) Plain docker run, no compose

scripts/run-docker.sh

Both bring up the voj.web and voj.judger containers and persist the database in a named volume, so the web UI is available at and your data survives image updates. run-docker.sh also generates strong random secrets and prints them once; to run the prebuilt Docker Hub images instead of building locally, use VOJ_PULL=1 scripts/run-docker.sh (or docker compose up, which pulls by default).

Configuration (database, mail, URLs, the judger token) is read from VOJ_* environment variables at runtime, so you can reconfigure or sit behind a reverse proxy without rebuilding. See docker/README.md for the full configuration, persistence and reverse-proxy details.

Build from source

Web application produces a self-contained executable JAR (embedded Tomcat):

cd web
mvn package -DskipTests        # -> web/target/voj.web.jar
java -jar target/voj.web.jar

Judger builds a Spring Boot jar plus the JNI native library, so a C++ toolchain is required:

# Linux build prerequisites: g++, make and libseccomp
sudo apt-get install -y g++ make libseccomp-dev

cd judger mvn package -DskipTests # -> judger/target/voj.judger.jar

On some JDK layouts the JNI build needs jnimd.h / jawtmd.h copied from
$JAVAHOME/include/linux (or .../win32) up into $JAVAHOME/include.

Convenience wrappers live in scripts/: build-jars.sh, build-docker.sh, run-web.sh and run-judger.sh (the run scripts preflight MySQL/ActiveMQ and import sql/schema.sql, sql/seed.sql and sql/demo.sql on first launch).

Both components read a voj.properties file (database, mail, message queue, sandbox, etc.). See docs/configuration.md for the full property reference.

Requirements

| Component | Requirement | | --- | --- | | Java | JDK 17+ (tested through JDK 25) | | Database | MySQL 8.0+ or MariaDB 10.4+ | | Message queue | ActiveMQ 6.0+ (Jakarta JMS) | | Judger (Linux build) | GCC/g++, make, libseccomp | | Judger OS | Linux or Windows |

Security model

Untrusted submissions run inside a sandbox so they cannot harm the judging host:

  • Linux (native). Each submission runs in a forked child with setrlimit
(CPU time, output size and process-count caps), accurate CPU-time and peak-memory accounting via wait4/getrusage, a private network namespace, a seccomp syscall filter (blocking ptrace, mount, module loading, etc.) and privileges dropped to an unprivileged user (system.username, defaulting to nobody). If the judger runs as root and cannot drop privileges, the submission is refused rather than run as root.
  • Linux (isolate). Optionally set judger.sandbox = isolate to delegate to the
external isolate tool instead.
  • Windows (native). Each submission runs under a separate low-privilege Windows
account (CreateProcessWithLogonW) inside a Job Object that caps the process count (anti fork-bomb), enforces memory and wall-clock limits, applies UI restrictions (no access to the interactive desktop or clipboard), and kills the whole process tree when the run ends.

The native sandbox does not provide full filesystem isolation. Reference answers and configuration are protected by file permissions (the work directory is handed to the sandbox user, while the checkpoint directory stays readable only by the judger), but a submission can still read world-readable host files. For complete filesystem isolation, run the judger as root with judger.sandbox = isolate, which confines each submission to its own mount namespace.

For shared, multi-tenant hosts, create a dedicated unprivileged account for system.username instead of reusing nobody. See docs/deployment.md for the filesystem layout and permissions a root deployment expects.

The origin of "Verwandlung"

In 2011, LinkedIn released the Kafka message queue, named after the author Franz Kafka. A year later, Alibaba introduced MetaQ, built on Kafka, a nod to Kafka's novella Metamorphosis. Since the message queue is central to this application, it took the name "Verwandlung", the German title of Metamorphosis.

Contributing

Contributions are welcome:

  • Report bugs and request features on the issues page.
  • For new features, please open an issue to discuss before sending a pull request.
  • Translators for additional languages are especially appreciated.

License

This project is open-sourced under the GNU GPL v3.

🔗 More in this category

© 2026 GitRepoTrend · hzxie/voj · Updated daily from GitHub