Skip to main content
Platforms

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