Run it in Docker
The Orchestrator runs as a container of curiosityai/orchestrator (:latest, or :<version>) for linux/amd64 and linux/arm64. It does not run Docker itself. It drives the host's Docker through the socket you mount into it, so the workspaces are containers next to it on the host, not inside it. They keep running when the Orchestrator's container is stopped, upgraded or removed.
Run it
docker run -d --name curiosity-orchestrator --restart unless-stopped \
-p 443:443 -p 80:8080 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v curiosity-orchestrator-data:/data \
-e ORC_ADMIN_PASSWORD='choose-a-password' \
-e ORC_CERT_SELF_SIGNED=true -e ORC_PORT=443 -e ORC_PORT_LOCAL=8080 -e ORC_REDIRECT_TO_HTTPS=true \
-e ORC_PUBLIC_ADDRESS=https://workspaces.example.com \
--stop-timeout 60 \
curiosityai/orchestrator:latest
This serves HTTPS with a self-signed certificate and redirects plain HTTP to it. For a first look over plain HTTP, publish -p 8080:8080 and set only ORC_ADMIN_PASSWORD, then open http://localhost:8080/#/manage.
What each part does
| Part | Why |
|---|---|
-v /var/run/docker.sock:/var/run/docker.sock |
Gives the Orchestrator access to the host's Docker. Without it, the console's overview says it cannot reach the Docker daemon. |
-v curiosity-orchestrator-data:/data |
The Orchestrator's state: its RocksDB database and certificates. Without a volume it forgets its workspaces when the container is re-created. |
--stop-timeout 60 |
The image runs the Orchestrator under tini, so a stop is a clean shutdown. 60 seconds is time to finish what it was doing. |
ORC_PUBLIC_ADDRESS |
The URL visitors use. It is named in the self-signed certificate. |
The Docker socket is root on the host
Access to /var/run/docker.sock is equivalent to root on the host. Treat the Orchestrator's container the same way.
Other Docker setups
- Rootless Docker: mount
$XDG_RUNTIME_DIR/docker.sockinstead. - Docker over TCP: set
ORC_DOCKER_ENDPOINT=tcp://host:2375and mount nothing.
How it reaches the workspaces
Inside a container, the Orchestrator reaches each workspace by container name (ORC_CONTAINER_ACCESS=network, set in the image). At start it joins its own container to the workspaces' network (ORC_DOCKER_NETWORK, created if missing), so only the Orchestrator's own ports are published.
If joining fails, the log says so. Connect it by hand:
docker network connect curiosity-orchestrator curiosity-orchestrator
The workspaces' containers and volumes are named ORC_CONTAINER_PREFIX (curiosity-) plus their address. Do not run two Orchestrators against one Docker daemon with the same prefix and network.
Docker Compose
services:
orchestrator:
image: curiosityai/orchestrator:latest
restart: unless-stopped
environment:
- ORC_ADMIN_PASSWORD=${ORC_ADMIN_PASSWORD:?Set ORC_ADMIN_PASSWORD}
- ORC_PUBLIC_ADDRESS=${ORC_PUBLIC_ADDRESS:-https://localhost}
- ORC_CERT_SELF_SIGNED=true
- ORC_PORT=443
- ORC_PORT_LOCAL=8080
- ORC_REDIRECT_TO_HTTPS=true
ports:
- "443:443"
- "80:8080"
volumes:
- orchestrator-data:/data
- /var/run/docker.sock:/var/run/docker.sock
stop_grace_period: 1m
volumes:
orchestrator-data:
ORC_ADMIN_PASSWORD='choose-a-password' docker compose up -d
For certificates from Let's Encrypt, prepare DNS and the firewall as in Run it on a server, then replace the environment section:
environment:
- ORC_ADMIN_PASSWORD=${ORC_ADMIN_PASSWORD:?Set ORC_ADMIN_PASSWORD}
- ORC_PUBLIC_ADDRESS=https://workspaces.example.com
- ORC_PORT=443
- ORC_PORT_HTTP=8080 # the port published as 80: Let's Encrypt, and the redirect to HTTPS
- ORC_LETSENCRYPT=true
- ORC_LETSENCRYPT_EMAIL=ops@example.com
- ORC_LETSENCRYPT_ACCEPT_TERMS=true
- ORC_LETSENCRYPT_STAGING=true # remove once it works
To switch from staging to real certificates, remove the staging line and delete the staging certificates from the data volume:
docker compose stop
docker compose run --rm --entrypoint rm orchestrator -rf /data/letsencrypt
docker compose up -d
Upgrade
docker pull curiosityai/orchestrator:latest
Then remove and re-run the container with the same volume. Workspaces that were running keep running, and the new Orchestrator picks them up.