Container Runner
Run any containerized server as a Rivet Actor.
The container runner (rivet-container-runner) runs as your container’s entrypoint, spawning your server as a child process and proxying gateway HTTP and WebSocket traffic to it. It is the recommended way to run non-RivetKit software, such as Unity or Godot dedicated game servers, behind Rivet. Each actor gets its own child process; the pool’s request concurrency decides how many actors share a container, and game servers should use one actor per container.
Steps
Prerequisites
- A containerized server (a Unity or Godot dedicated server, a plain Node process, or any HTTP/WebSocket server)
- Access to the Rivet Cloud or a self-hosted Rivet Engine
- Docker running locally
Install in Your Container
Download the static binary from Rivet’s release artifacts in your Dockerfile and set it as the entrypoint, passing your server’s launch command after --:
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
# Install the Rivet container runner.
RUN curl -fsSL https://releases.rivet.dev/rivet/latest/container-runner/rivet-container-runner-x86_64-unknown-linux-musl \
-o /usr/local/bin/rivet-container-runner \
&& chmod +x /usr/local/bin/rivet-container-runner
# Your server binary and assets.
COPY build/ /game/
WORKDIR /game
ENTRYPOINT ["rivet-container-runner", "--", "./GameServer", "-batchmode", "-nographics", "-logFile", "-"]
Artifacts are published for x86_64-unknown-linux-musl and aarch64-unknown-linux-musl. The binaries are fully static, so they run in any Linux base image, including scratch. Pin a version by replacing latest with a release version, for example https://releases.rivet.dev/rivet/2.3.3/container-runner/rivet-container-runner-x86_64-unknown-linux-musl.
Deploy
Deploy the image to Rivet Compute with the CLI. For game servers, configure the pool with one actor per instance:
npx @rivetkit/cli deploy \
--token "$RIVET_CLOUD_TOKEN" \
--instance-request-concurrency 1 \
--dockerfile Dockerfile
Create Actors and Connect Clients
Create actors against the pool’s runner (default) and connect clients through the gateway URL shown in the dashboard. WebSocket clients connect at the bare gateway URL with the rivet WebSocket subprotocol.
How It Works
- The engine cold-starts your container and calls
POST /api/rivet/starton the port it injects asRIVET_PORT. - The runner spawns your server as a child process with
PORTset to the child port, waits for the port to open, and reports the actor as running. - Gateway traffic for the actor arrives over Rivet’s tunnel and is proxied to
127.0.0.1:<child port>. WebSocket clients connect at the bare gateway URL with therivetWebSocket subprotocol. Raw HTTP reaches the child under the/request/*prefix on the actor surface (the prefix is stripped before proxying); other paths are reserved for the runtime’s own endpoints. - Child stdout and stderr are re-emitted with an
[actorId=... key=...]prefix so actor logs are attributed in the dashboard. - When an actor stops, the runner sends its child
SIGTERM, escalates toSIGKILLafter a grace period, and exits the process once no actors remain.
Configuration
All flags can also be set through environment variables:
| Flag | Environment variable | Default | Description |
|---|---|---|---|
--port | RIVET_PORT / PORT | 8080 | Serverless front-door HTTP port. Rivet Compute injects RIVET_PORT automatically. |
--child-port | CHILD_PORT | 7770 | First local child port; each actor’s child gets the next free port at or above this, exported to the child as PORT. |
--actor-name | RIVET_ACTOR_NAME | game | Actor name this runner serves. |
--runner-version | RIVET_RUNNER_VERSION | 1 | Version reported to the engine, used to drain old runners on deploy. |
--base-path | RIVET_SERVERLESS_BASE_PATH | /api/rivet | Base path the engine calls for serverless start. |
--stop-grace-secs | RIVET_STOP_GRACE_SECS | 25 | SIGTERM to SIGKILL grace period when stopping the child. Capped to a few seconds when the platform itself is reclaiming the instance, so shutdown fits inside the platform’s own kill window. |
--readiness-timeout-secs | RIVET_READINESS_TIMEOUT_SECS | 30 | How long to wait for the child’s port to open before failing the start. |
Per-Actor Input
The actor’s input payload can override the launch spec per actor. All fields are optional and fall back to the entrypoint command. RivetKit clients pass this object directly; when creating actors through the raw engine API, encode it as CBOR before base64-encoding the input field:
{
"command": ["./GameServer", "-batchmode"],
"args": ["-extra-flag"],
"env": { "MATCH_MODE": "ranked" }
}
command replaces the entrypoint command template, args are appended to it, and env adds environment variables for the child.
Source and Examples
The runner and a full end-to-end example, including a Unity FishNet demo project and a local test harness, live in the Rivet repository under container-runner/.