VM & Bare Metal
Run the Rivet control plane on a Linux host with Docker.
Requirements
- A Linux host with SSH access and Docker installed
- A persistent disk for the data volume
This guide covers any Linux host: Hetzner, DigitalOcean, Linode, EC2, or hardware you own.
Steps
Generate an admin token
export RIVET_ADMIN_TOKEN=$(openssl rand -hex 32)
echo $RIVET_ADMIN_TOKEN
Save it. Without a token the API is unauthenticated.
Start the control plane
docker run -d \
--name rivet-engine \
--restart unless-stopped \
-p 6420:6420 \
-p 6421:6421 \
-v rivet-data:/data \
-e RIVET__FILE_SYSTEM__PATH="/data" \
-e RIVET__AUTH__ADMIN_TOKEN="$RIVET_ADMIN_TOKEN" \
rivetdev/engine:latest
The named volume is what makes data survive a container replacement. Pin the image tag for anything long-lived.
Verify
curl -i http://localhost:6421/health
Expect 200. The dashboard is at http://<host>:6420/ui.
Create the runner config
A runner config declares a pool that workers connect to. Without one the control plane refuses every worker, so create it before deploying any:
curl -X PUT "http://<host>:6420/runner-configs/default?namespace=default" \
-H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"datacenters":{"default":{"normal":{}}}}'
Use normal for long-lived workers. See Runner configs.
Put TLS in front
Port 6420 should not be exposed directly to the internet. Terminate TLS at NGINX or Caddy and raise the idle timeout to 3600 seconds, or long-lived WebSockets will be cut. See TLS.
Connect a worker
From another host, point the worker at this one:
RIVET_ENDPOINT="http://default:$RIVET_ADMIN_TOKEN@your-host.example.com:6420"
From a container on the same host, use host.docker.internal instead of the hostname. Confirm the worker appears under Runners in the dashboard.
Using PostgreSQL
The file system backend above is RocksDB on local disk: single-node, and impossible to share between hosts. Scaling past one control plane node means moving to PostgreSQL first, then adding NATS for pub/sub. See Storage. The commands below are still one engine container on one host; PostgreSQL is what makes adding a second host possible later.
docker network create rivet-net
docker run -d --name postgres --network rivet-net \
-e POSTGRES_DB=rivet -e POSTGRES_USER=rivet -e POSTGRES_PASSWORD=rivet_password \
-v postgres-data:/var/lib/postgresql/data \
postgres:15
docker run -d --name rivet-engine --network rivet-net \
--restart unless-stopped \
-p 6420:6420 -p 6421:6421 \
-e RIVET__POSTGRES__URL="postgresql://rivet:rivet_password@postgres:5432/rivet" \
-e RIVET__AUTH__ADMIN_TOKEN="$RIVET_ADMIN_TOKEN" \
rivetdev/engine:latest
Using a config file
docker run -d \
--name rivet-engine \
-p 6420:6420 \
-v rivet-data:/data \
-v $(pwd)/rivet-config.json:/etc/rivet/config.json:ro \
rivetdev/engine:latest
See Configuration for the full schema.
Building from source
git clone https://github.com/rivet-dev/rivet.git
cd rivet
cargo build --release -p rivet-engine
./target/release/rivet-engine
Next steps
- Production checklist
- Docker Compose for multi-container setups
- Configuration reference