Run the Gateway with Docker Compose

View as Markdown

This tutorial shows how to run the OpenShell gateway as a Docker Compose service on a Linux host or on a machine running Docker Desktop (Windows or macOS).

After completing this tutorial you have:

  • An OpenShell gateway running as a Compose service.
  • The openshell CLI registered against that gateway.
  • An AI provider configured with your API key.
  • A running OpenClaw sandbox.

Prerequisites

  • Docker Desktop (Windows or macOS) or Docker Engine with the Compose plugin (Linux).
  • The openshell CLI installed on your workstation. See Install the CLI below.
  • Port 8080 available on the host.

Compose files

The Compose configuration lives at deploy/docker/ in the repository.

FilePurpose
docker-compose.ymlGateway service, volumes, and environment variables
gateway.tomlTOML reference for release builds with config-file support

Port note

The Docker compute driver injects host.openshell.internal:<gateway-port> into every sandbox container as its callback address. The gateway listens on port 8080 inside the container, so port 8080 must be published at the same number on the Docker host. Publishing it as a different host port (for example 18080:8080) causes sandbox containers to call back to the wrong port and remain stuck in the Provisioning phase.

If port 8080 is taken, change OPENSHELL_SERVER_PORT and update the port mapping to <your-port>:8080, then set OPENSHELL_PORT=<your-port> in an .env file.

Data directory

The gateway extracts the openshell-sandbox supervisor binary from ghcr.io/nvidia/openshell/supervisor:latest on first start and caches it at:

/var/lib/openshell/openshell/docker-supervisor/<digest>/openshell-sandbox

This path is used as a bind-mount source when Docker creates sandbox containers. Docker resolves bind-mount sources against the host filesystem, not the container filesystem, so the data directory must be bind-mounted at the same absolute path in both the host and the container.

The Compose file uses /var/lib/openshell for this purpose and sets create_host_path: true so Docker creates it on first run.

Start the gateway

$cd deploy/docker
$docker compose up -d

Verify the gateway is healthy:

$curl -sf http://localhost:8080/healthz

Install the CLI

Binary (recommended — macOS / Linux / WSL):

$curl -LsSf https://raw.githubusercontent.com/NVIDIA/OpenShell/main/install.sh | sh

From PyPI (any platform with uv):

$uv tool install -U openshell

On Windows without WSL, install the CLI inside a WSL 2 distribution (for example AlmaLinux or Ubuntu) and run all openshell commands from that distribution.

Register the gateway

Run this once after the gateway starts:

$openshell gateway add http://localhost:8080 --name openshell-docker

Verify the connection:

$openshell status

The output should show Status: Connected.

Configure an AI provider

Set your API key as an environment variable and create a provider:

$ANTHROPIC_API_KEY=sk-ant-... \
> openshell provider create --name anthropic --type anthropic --from-existing

Confirm the provider was stored:

$openshell provider list

Pre-pull sandbox images (optional)

Sandbox images are pulled automatically on first use, but the initial pull can take several minutes for large images. Pre-pull to avoid long waits at sandbox creation time:

$# Base image — includes Claude Code, OpenCode, Codex, and Copilot
$docker pull ghcr.io/nvidia/openshell-community/sandboxes/base:latest
$
$# OpenClaw image
$docker pull ghcr.io/nvidia/openshell-community/sandboxes/openclaw:latest

Create a sandbox

$openshell sandbox create --from openclaw

OpenClaw launches directly. The first run pulls the image if it is not cached.

Wait for the phase to change from Provisioning to Ready:

$openshell sandbox list

Then connect:

$openshell sandbox connect <sandbox-name>

Manage the gateway

CommandPurpose
docker compose up -dStart or restart the gateway
docker compose downStop the gateway and remove the container
docker compose logs -fTail gateway logs
docker compose pullPull a new gateway image version

Linux notes

On Linux, host.docker.internal and host.openshell.internal are not automatically resolvable from containers. Add the following under the gateway service in docker-compose.yml:

1extra_hosts:
2 - "host.docker.internal:host-gateway"
3 - "host.openshell.internal:host-gateway"

Next steps