Unity
Run a Unity dedicated server as a Rivet Actor with the container runner and connect clients over WebSockets.
Rivet runs a Unity dedicated server build as a Rivet Actor: one actor per match, cold-started on demand and shut down when the match ends. The server ships in a container with the container runner as its entrypoint. Your Unity project does not link against RivetKit.
The container runner proxies HTTP and WebSocket traffic only, so your netcode needs a WebSocket transport. This guide uses FishNet with the Bayou WebSocket transport, which is what the Unity example in the Rivet repository uses.
Steps
Prerequisites
- Unity 6 with the Linux Dedicated Server Build Support module installed
- Docker running locally
- A Rivet Cloud namespace with a secret token (
sk_) and a public token (pk_)
Configure the Server
Add FishNet and Bayou to your project, then make the server read its port from the PORT environment variable. The container runner sets PORT for each actor it launches. Add a bootstrap component next to your NetworkManager:
using FishNet.Managing;
using UnityEngine;
public class ServerBootstrap : MonoBehaviour
{
private void Start()
{
var nm = GetComponent<NetworkManager>();
var portEnv = System.Environment.GetEnvironmentVariable("PORT");
ushort port = ushort.TryParse(portEnv, out var p) ? p : (ushort)7770;
nm.TransportManager.Transport.SetPort(port);
nm.ServerManager.StartConnection();
}
}
Set Bayou as the active transport on the TransportManager. The server side needs nothing else: the container runner connects to it at ws://127.0.0.1:<PORT>/ with a plain WebSocket handshake.
Configure the Client
Clients reach an actor through the Rivet gateway at a URL that carries the actor ID and your public token in the path:
wss://api.rivet.dev/gateway/<actor_id>@pk_xxxxx/
Stock Bayou always connects to /, so it cannot address a specific actor. The Unity example patches Bayou to accept a client path and WSS. Copy the Packages/com.firstgeargames.fishnet.bayou package from the example into your project, then set the path before connecting:
var uri = new System.Uri(gatewayUrl);
bayou.SetUseWSS(uri.Scheme == "wss");
bayou.SetClientPath(uri.PathAndQuery);
nm.TransportManager.Transport.SetClientAddress(uri.Host);
nm.TransportManager.Transport.SetPort((ushort)(uri.IsDefaultPort ? 443 : uri.Port));
nm.ClientManager.StartConnection();
Build the Server
Build a Linux x86_64 dedicated server (Build Profiles, Linux Server platform) into Builds/ServerLinux/. The output is the GameServer executable, GameServer_Data/, and UnityPlayer.so. Unity builds can also be scripted; see setup-and-build.sh linux in the example.
Write the Dockerfile
Wrap the build with the container runner. -logFile - sends Unity logs to stdout so they appear in the Rivet dashboard.
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates curl && rm -rf /var/lib/apt/lists/*
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
COPY Builds/ServerLinux/ /game/
WORKDIR /game
RUN chmod +x /game/GameServer
ENTRYPOINT ["rivet-container-runner", "--", "./GameServer", "-batchmode", "-nographics", "-logFile", "-"]
If the server logs a missing shared object at startup, add that library to the apt-get install line.
Deploy
npx @rivetkit/cli deploy \
--token "$RIVET_CLOUD_TOKEN" \
--instance-request-concurrency 1 \
--drain-on-version-upgrade false \
--dockerfile Dockerfile
--instance-request-concurrency 1 runs one match per container. --drain-on-version-upgrade false lets running matches finish when you deploy a new version.
Create a Match and Connect
Your backend or matchmaker creates one actor per match with the secret token, then hands the actor ID to players:
curl -X POST "https://api.rivet.dev/actors?namespace=my-namespace" \
-H "Authorization: Bearer sk_xxxxx" \
-H "Content-Type: application/json" \
-d '{"name":"game","key":"match-1234","runner_name_selector":"default","crash_policy":"destroy"}'
Players connect to wss://api.rivet.dev/gateway/<actor_id>@pk_xxxxx/. The first connection cold-starts the container; the gateway holds the connection until the server’s port opens.
Next Steps
- Containers for runner flags, per-actor launch overrides, and how traffic is proxied
- Unity example with the patched Bayou transport, build script, and Dockerfile
- Authentication for public and secret tokens