> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/openshell/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/openshell/_mcp/server.

# Running the Gateway as a Container

> Run the OpenShell gateway using docker run or docker-compose without the installer.

Use this approach when you want to run the OpenShell gateway as a container instead of installing it with the system package manager. This is useful on immutable OS distributions (Fedora CoreOS, bootc-based images, Silverblue) where the standard installer is not appropriate, or anywhere you prefer a container-first workflow.

The gateway image is published at `ghcr.io/nvidia/openshell/gateway`.

## Prerequisites for the Docker Driver

When the gateway runs as a container and creates Docker-backed sandboxes, the gateway container
communicates with the host Docker daemon via the mounted socket. This requires three things beyond
a basic `docker run`:

1. **Docker socket access.** The gateway process must be able to read and write the Docker socket.
   Add the `docker` group (or the GID of `/var/run/docker.sock`) so the socket is accessible
   without running as root.

2. **gRPC endpoint.** Sandbox containers call back to the gateway over the `OPENSHELL_GRPC_ENDPOINT`
   address. The Docker driver substitutes `host.openshell.internal` as the host and the gateway's
   own bind port as the port — only the **scheme** (`http` or `https`) is preserved. Use
   `http://host.openshell.internal:8080` when TLS is disabled and `https://host.openshell.internal:8080`
   when mTLS is enabled. The docker driver automatically binds the gateway to the bridge network
   interface so sandbox containers can reach it — you do not need to expose the port on `0.0.0.0`.

3. **Supervisor binary on the host.** The gateway bind-mounts the `openshell-sandbox` supervisor
   binary into each sandbox container. Because bind-mount paths are resolved by the host Docker
   daemon (not inside the gateway container), the binary must exist at a path on the **host**
   filesystem and be mounted at the **same absolute path** inside the gateway container. That way
   the path the gateway records internally matches what Docker can find on the host when it
   creates sandbox containers.

## Quick Start

Extract the supervisor binary to the host once, then start the gateway:

```shell
mkdir -p ~/openshell/supervisor
docker create --name tmp-supervisor ghcr.io/nvidia/openshell/supervisor:latest
docker cp tmp-supervisor:/openshell-sandbox ~/openshell/supervisor/openshell-sandbox
docker rm tmp-supervisor
chmod +x ~/openshell/supervisor/openshell-sandbox
```

Start the gateway:

```shell
docker run -d \
  --name openshell-gateway \
  --restart unless-stopped \
  --group-add docker \
  -p 127.0.0.1:8080:8080 \
  -v openshell-state:/var/openshell \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v ~/openshell/supervisor/openshell-sandbox:~/openshell/supervisor/openshell-sandbox:ro \
  -e OPENSHELL_COMPUTE_DRIVER=docker \
  -e OPENSHELL_GRPC_ENDPOINT=http://host.openshell.internal:8080 \
  -e OPENSHELL_DOCKER_SUPERVISOR_BIN=~/openshell/supervisor/openshell-sandbox \
  -e OPENSHELL_DB_URL=sqlite:/var/openshell/openshell.db \
  -e OPENSHELL_DISABLE_TLS=true \
  ghcr.io/nvidia/openshell/gateway:latest
```

The volume mount uses `~/openshell/supervisor/openshell-sandbox` for both the host and container
paths. The shell expands `~` in both halves before passing the argument to Docker, so both sides
resolve to the same absolute path (e.g., `/home/user/openshell/supervisor/openshell-sandbox`).
This satisfies the same-path requirement so the host Docker daemon can find the binary when
creating sandbox containers.

Register the gateway with the CLI. If running on the same machine, use `--local`:

```shell
openshell gateway add http://127.0.0.1:8080 --local --name local
```

If registering from a different machine on the same network, use the host IP and `--remote`:

```shell
openshell gateway add http://HOST_IP:8080 --remote --name remote
```

Confirm the CLI can reach the gateway:

```shell
openshell status
```

Disabling TLS removes authentication. This example binds to `127.0.0.1` so only local
connections are accepted. To accept remote connections, enable mTLS or restrict access with
a firewall rule.

## Full mTLS Setup

To run the gateway with mutual TLS, generate the PKI bundle first, then start the gateway with the cert paths configured.

Bootstrap the PKI into a local state directory:

```shell
mkdir -p ~/.local/state/openshell/tls

docker run --rm \
  -v "$HOME/.local/state/openshell:/home/openshell/.local/state/openshell" \
  -v "$HOME/.config/openshell:/home/openshell/.config/openshell" \
  ghcr.io/nvidia/openshell/gateway:latest \
  generate-certs \
    --output-dir /home/openshell/.local/state/openshell/tls \
    --server-san host.openshell.internal
```

This writes the server and client certificates under `~/.local/state/openshell/tls/`, writes sandbox JWT signing keys under `~/.local/state/openshell/tls/jwt/`, and copies the client bundle to `~/.config/openshell/gateways/openshell/mtls/` so the CLI picks it up automatically.

Start the gateway with mTLS enabled:

```shell
docker run -d \
  --name openshell-gateway \
  --restart unless-stopped \
  --group-add docker \
  -p 127.0.0.1:8080:8080 \
  -v "$HOME/.local/state/openshell:/home/openshell/.local/state/openshell" \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v ~/openshell/supervisor/openshell-sandbox:~/openshell/supervisor/openshell-sandbox:ro \
  -e OPENSHELL_COMPUTE_DRIVER=docker \
  -e OPENSHELL_GRPC_ENDPOINT=https://127.0.0.1:8080 \
  -e OPENSHELL_DOCKER_SUPERVISOR_BIN=~/openshell/supervisor/openshell-sandbox \
  -e OPENSHELL_DB_URL=sqlite:/home/openshell/.local/state/openshell/openshell.db \
  -e OPENSHELL_LOCAL_TLS_DIR=/home/openshell/.local/state/openshell/tls \
  -e OPENSHELL_TLS_CERT=/home/openshell/.local/state/openshell/tls/server/tls.crt \
  -e OPENSHELL_TLS_KEY=/home/openshell/.local/state/openshell/tls/server/tls.key \
  -e OPENSHELL_TLS_CLIENT_CA=/home/openshell/.local/state/openshell/tls/ca.crt \
  -e OPENSHELL_ENABLE_MTLS_AUTH=true \
  -e OPENSHELL_DOCKER_TLS_CA=/home/openshell/.local/state/openshell/tls/ca.crt \
  -e OPENSHELL_DOCKER_TLS_CERT=/home/openshell/.local/state/openshell/tls/client/tls.crt \
  -e OPENSHELL_DOCKER_TLS_KEY=/home/openshell/.local/state/openshell/tls/client/tls.key \
  ghcr.io/nvidia/openshell/gateway:latest
```

Register the gateway with mTLS:

```shell
openshell gateway add https://127.0.0.1:8080 --local --name local
```

## Docker Compose

The [`deploy/docker/`](https://github.com/NVIDIA/OpenShell/tree/main/deploy/docker) directory in
the repository contains a production-ready Compose setup with full inline documentation:

| File                 | Purpose                                             |
| -------------------- | --------------------------------------------------- |
| `docker-compose.yml` | Gateway service, volumes, and environment variables |
| `gateway.toml`       | TOML configuration mounted into the container       |

Clone or copy those files, then start the gateway:

```shell
docker compose -f deploy/docker/docker-compose.yml up -d
```

Register the gateway with the CLI. If registering from the same machine:

```shell
openshell gateway add http://127.0.0.1:8080 --local --name local
```

If registering from a different machine on the same network, replace `HOST_IP` with the
machine's LAN address:

```shell
openshell gateway add http://HOST_IP:8080 --remote --name remote
```

## Using Podman

Replace `docker` with `podman` in the commands above. Mount the Podman socket instead of the Docker socket and set the driver to `podman`:

```shell
podman run -d \
  --name openshell-gateway \
  -p 127.0.0.1:8080:8080 \
  -v openshell-state:/var/openshell \
  -v "$XDG_RUNTIME_DIR/podman/podman.sock:/var/run/podman.sock" \
  -e OPENSHELL_COMPUTE_DRIVER=podman \
  -e OPENSHELL_PODMAN_SOCKET=/var/run/podman.sock \
  -e OPENSHELL_DB_URL=sqlite:/var/openshell/openshell.db \
  -e OPENSHELL_DISABLE_TLS=true \
  ghcr.io/nvidia/openshell/gateway:latest
```

## Next Steps

* To create your first sandbox, refer to the [Quickstart](/get-started/quickstart).
* To control what the agent can access, refer to [Policies](/sandboxes/policies).
* For environment variable reference, refer to [Sandbox Compute Drivers](/reference/sandbox-compute-drivers).