Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ohemilyy/universe/llms.txt

Use this file to discover all available pages before exploring further.

The runtime-docker extension replaces Universe’s default process-based runtimes (screen, tmux) with Docker containers. Each instance runs in its own container named universe-<instanceId>. The container’s working directory is bind-mounted from ./running/<instanceId>/, so template files are available exactly as they are on the host.

Installation

1

Place the JAR

Copy runtime-docker.jar into the ./extensions/ directory alongside your Universe JAR.
cp runtime-docker.jar ./extensions/
2

Create the config file

On first load, the extension reads ./extensions/runtime-docker/config.json. Create the directory and drop in a config file before starting Universe.
mkdir -p ./extensions/runtime-docker
3

Start Universe

Launch Universe normally. The extension is discovered automatically and registers itself under the "docker" runtime key.
java -jar universe-loader-0.0.1.jar
A success log line confirms the extension loaded:
[SUCCESS] Docker runtime extension loaded (image=azul-zulu:25-jdk-alpine)

Configuration

The extension reads ./extensions/runtime-docker/config.json. All fields are optional — the defaults work for a standard local Docker socket.
{
  "factoryName": "docker-jvm",
  "network": "host",
  "javaImage": {
    "repository": "azul-zulu",
    "tag": "25-jdk-alpine",
    "registry": null,
    "platform": null
  },
  "volumes": [],
  "binds": [],
  "exposedPorts": [],
  "dockerHost": "unix:///var/run/docker.sock",
  "dockerCertPath": null,
  "registryUsername": null,
  "registryEmail": null,
  "registryPassword": null,
  "registryUrl": null,
  "user": null,
  "containerWorkDir": "/app",
  "autoRemove": false,
  "stopTimeout": 10,
  "hostDataPath": null
}

Field reference

FieldTypeDefaultDescription
factoryNamestring"docker-jvm"Internal label for the Docker client factory.
networkstring"host"Docker network mode for all containers.
javaImage.repositorystring"azul-zulu"Image repository name.
javaImage.tagstring"25-jdk-alpine"Image tag to run.
javaImage.registrystring | nullnullOptional private registry prefix.
javaImage.platformstring | nullnullOptional platform, e.g. "linux/amd64".
volumesarray[]Structured volume mounts (see below).
bindsarray[]Raw bind strings in "host:container" or "host:container:ro" format.
exposedPortsarray[]Extra ports to expose beyond the allocated instance port.
dockerHoststring"unix:///var/run/docker.sock"Docker daemon socket or TCP address.
dockerCertPathstring | nullnullPath to TLS certificates for TLS-secured daemons.
registryUsernamestring | nullnullCredential for private registry pulls.
registryPasswordstring | nullnullCredential for private registry pulls.
registryEmailstring | nullnullCredential for private registry pulls.
registryUrlstring | nullnullPrivate registry URL.
userstring | nullnullUnix user to run the container process as.
containerWorkDirstring"/app"Working directory inside the container where the instance dir is mounted.
autoRemovebooleanfalseAutomatically remove the container after it stops. Set to false for debugging.
stopTimeoutint10Seconds to wait for graceful container shutdown before force-killing.
hostDataPathstring | nullnullRequired when Universe itself runs inside Docker. See note below.

Volume mounts

Use the volumes array for structured mounts:
"volumes": [
  {
    "hostPath": "/opt/plugins",
    "containerPath": "/app/plugins",
    "readOnly": true
  }
]
Or use binds for shorthand strings:
"binds": ["/opt/plugins:/app/plugins:ro"]

Running Universe inside Docker

When Universe runs inside a Docker container itself, bind mounts for instance working directories are resolved by the Docker daemon on the host filesystem, not inside the Universe container. Set hostDataPath to the absolute host path that corresponds to Universe’s data directory.
Example: Universe container mounts ./data:/data and the compose file lives at /opt/universe. Set hostDataPath: "/opt/universe/data" so child containers bind-mount the correct host path.

Using the Docker runtime

Set "runtime": "docker" in any instance configuration file under ./configuration/:
{
  "name": "my-server",
  "runtime": "docker",
  "command": "java -jar server.jar",
  "availablePorts": { "min": 25565, "max": 25570 }
}

Container lifecycle

DockerRuntimeProvider implements the full RuntimeProvider interface:
MethodBehaviour
start(instanceId, workingDir, port, command, ramMB, cpu)Pulls the image if not present locally, removes any stale container with the same name, creates and starts the container with the working directory bind-mounted, and verifies the container is still running after 1.5 s.
stop(instanceId)Sends a stop signal and waits up to stopTimeout seconds, then force-removes the container unless autoRemove is enabled.
executeCommand(instanceId, command)Runs the command string inside the running container via docker exec.
isRunning(instanceId)Inspects the container state and returns true if it is running.

Resource limits

Pass non-zero values for ramMB and cpu in the instance configuration to apply Docker resource limits:
  • ramMB — sets the container’s memory limit and disables swap.
  • cpu — sets nano-CPU units (100 units = 1 core of CPU time).

Port bindings

The allocated instance port is always mapped host:container at the same port number. Additional ports declared in exposedPorts are exposed but not bound to specific host ports.
"exposedPorts": [
  { "containerPort": 8080, "protocol": "tcp" },
  { "containerPort": 19132, "protocol": "udp" }
]

Private registry

Populate registryUsername, registryPassword, registryEmail, and registryUrl in the config to authenticate against a private registry before pulling images.

Build docs developers (and LLMs) love