Jobe self-hosting
Securing a Jobe server: firewall, Docker and API keys
A Jobe server runs any code it is sent. Left open, anyone who finds it can use your machine, and student code can reach your network. Jobe's documentation says to firewall it; on a Docker host the usual firewall doesn't apply, and in some Jobe versions API keys did nothing. Here is what actually protects it.
By the OnlineCompiler.io team. Updated . We make OnlineCompiler.io, so we're one of the options here. Every competitor figure links to the vendor's own page, and we say where our API falls short.
What Jobe's documentation recommends
Jobe's README asks for a dedicated server, firewalled so that only your Moodle server can connect, and with outgoing connections blocked so that student code can't scan your network. Its example uses ufw:
ufw default reject outgoing
ufw allow out proto tcp to <some_useful_ip> port 80,443
ufw allow in 22/tcp
ufw allow in proto tcp to any port 80 from <your_moodle_server_ip>
ufw enableOn a server where Jobe is installed directly, that does what it says. With no firewall and no API keys, anyone can run code on the machine.
ufw doesn't protect a jobeinabox container
If you run jobeinabox, the rules above leave the container exposed. Docker's own documentation says Docker and ufw are incompatible: traffic to and from a published container port is routed before it reaches the INPUT and OUTPUT chains that ufw uses. So on a jobeinabox host:
ufw allow in ... from <your_moodle_server_ip>does not stop other addresses reaching the published Jobe port.ufw default reject outgoingdoes not stop student code in the container connecting out.
Use one of these instead:
- A firewall outside the machine: your cloud provider's security group or firewall, or a network firewall, allowing only your Moodle server in and nothing out except what Jobe needs.
- Rules in Docker's
DOCKER-USERchain, which Docker evaluates before its own (Docker with iptables). - Publishing the port only on a private interface or address that Moodle reaches over your internal network.
Test from a machine that isn't your Moodle server: a request to /jobe/index.php/restapi/languages should fail. Blocking outgoing traffic also settles the worry raised in jobe#87, of exam
candidates downloading answers from inside a run.
Jobe API keys
Keys are set in app/Config/Jobe.php on Jobe 2. Each key maps to the runs per hour it allows, and
CodeRunner sends its Jobe API key setting in the X-API-KEY header:
// /var/www/html/jobe/app/Config/Jobe.php
public bool $require_api_keys = true;
public array $api_keys = [
'a-long-random-key-only-your-moodle-knows' => 0, // runs per hour; 0 = unlimited
];- Only
POST /restapi/runsis checked. Listing languages and uploading files work without a key. - A missing or unknown key gets 403; going over the rate gets 429. The rate is counted per client address, so behind a reverse proxy every request may look like it comes from the proxy.
- Jobe 2.2.0 and 2.2.1 did not check keys at all. A framework upgrade in September 2025 dropped the check, and 2.2.2 (6 April 2026) restored it. If you turned keys on in that window, upgrade and test that a request without a key now gets 403.
- Delete the sample key
2AAA7A5415B4A9B394B54BF1D2E9Dfrom the config. It is public, and it is also the key every CodeRunner install ships with, so anyone who finds your server already has it. - jobeinabox can take keys at build time from a secrets file (
--secret id=api_keys,...), as its README describes.
Jobe's README calls keys rarely useful: they are for servers that must be open to many clients. For one Moodle site, the firewall is the control that matters.
"Sandbox submission limit reached" after adding a password
Putting Jobe behind web server Basic authentication looks like an easy lock (jobe#79):
<Location />
AuthType Basic
AuthUserFile /var/www/html/.htpasswd
Require valid-user
</Location>CodeRunner then reports Sandbox submission limit reached on every question. The web server answers 401 without the password, CodeRunner maps any 401 to that message, and it has no setting for a username and password. Jobe's maintainer pointed the reporter back to the firewall. Remove the Basic auth block, then use a firewall that admits only your Moodle server, or API keys on Jobe 2.2.2 or later.
What CodeRunner shows for each answer from Jobe, from CodeRunner's source:
| Jobe answers | CodeRunner shows |
|---|---|
| 401 (for example from web server Basic auth) | Sandbox submission limit reached |
| 403 Missing API key / Unknown API key | Unauthorised to use sandbox |
| 429 Max RUN rate for this server exceeded | Jobe server request failed. HTTP response from Jobe was 429 ... |
| Outcome 21 (no free Jobe user) | Job could not be run due to server overload. Perhaps try again shortly? |
| Moodle blocked the address | The URL is blocked. Check the Jobe URL and Moodle's HTTP security settings. |
Keep it updated
Jobe 2.2.3 (3 September 2026) fixed attacks through a job's output files and a way for one Jobe user to act as another, and a jobeinabox build fix the same day corrected runguard's file ownership, which had allowed the web server user to become root. Run Jobe 2.2.3 or later, and if you use jobeinabox, rebuild from a version after 3 September 2026. Rebuild regularly for operating system and compiler updates too.
Or let someone else run the sandbox
A hosted Jobe-compatible server takes the firewall, the updates and the sandbox off your list. OnlineCompiler.io
runs every CodeRunner job in a fresh gVisor sandbox with no network access, 512 MB of memory and a
30-second limit, and throws it away afterwards; access is by API key, with limits per
account. Set CodeRunner's Jobe server to https://api.onlinecompiler.io/api and its Jobe API key to an OnlineCompiler.io key. The free plan includes 100,000 runs a month.
The security page explains the sandbox, the Jobe-compatible API page lists the differences from Jobe, and CodeRunner without a Jobe server has the setup.
Frequently asked questions
Why does CodeRunner say "Sandbox submission limit reached" after I added a password to Jobe?
Your web server answers 401 when the password is missing, and CodeRunner reports any 401 from Jobe as a submission limit. CodeRunner has no setting for a username and password; the only credential it sends is the X-API-KEY header. Remove the password and restrict access with a firewall or Jobe's API keys.
Does ufw protect a Jobe server running in Docker?
Not for the container's published port. Docker routes traffic to and from published container ports before ufw's rules see it, so ufw neither limits who reaches Jobe nor stops student code connecting out. Use a cloud or network firewall in front of the machine, or rules in Docker's DOCKER-USER chain.
I turned on require_api_keys but requests without a key still run. Why?
Jobe 2.2.0 and 2.2.1 (September 2025 to April 2026) did not check API keys at all, because of a change during a framework upgrade. Jobe 2.2.2 fixed it. Upgrade, or rebuild jobeinabox from a version after 6 April 2026.
Do I need API keys if my Jobe server is firewalled?
Usually not. Jobe's own documentation calls them rarely useful and recommends a firewall that only lets your Moodle server in. Keys matter when the server must be reachable by many clients.
Who looks after this on a hosted Jobe-compatible server?
The provider. On OnlineCompiler.io every run gets a fresh gVisor sandbox with no network access, 512 MB of memory and a 30-second limit, and access is by API key. Set CodeRunner's Jobe server to https://api.onlinecompiler.io/api; the free plan includes 100,000 runs a month.