> ## Documentation Index
> Fetch the complete documentation index at: https://docs.openhands.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Runtime

> This is the default Runtime that's used when you start OpenHands.

<Note>
  This page documents **legacy OpenHands V0** behavior. For the current V1
  sandbox model, see [Sandboxes (V1)](/openhands/usage/sandboxes/overview).
</Note>

## Image

The runtime image from nikolaik is a pre-built runtime image
that contains our Runtime server, as well as some basic utilities for Python and NodeJS.
You can specify a custom runtime image using the `AGENT_SERVER_IMAGE_REPOSITORY` and `AGENT_SERVER_IMAGE_TAG` environment variables.
You can also [build your own runtime image](/openhands/usage/advanced/custom-sandbox-guide).

## Connecting to Your filesystem

A useful feature is the ability to connect to your local filesystem. To mount your filesystem into the runtime:

### Using SANDBOX\_VOLUMES

The simplest way to mount your local filesystem is to use the `SANDBOX_VOLUMES` environment variable:

```bash theme={null}
export SANDBOX_VOLUMES=/path/to/your/code:/workspace:rw

docker run # ...
    -e SANDBOX_USER_ID=$(id -u) \
    -e SANDBOX_VOLUMES=$SANDBOX_VOLUMES \
    # ...
```

The `SANDBOX_VOLUMES` format is `host_path:container_path[:mode]` where:

* `host_path`: The path on your host machine that you want to mount.
* `container_path`: The path inside the container where the host path will be mounted.
  * Use `/workspace` for files you want the agent to modify. The agent works in `/workspace` by default.
  * Use a different path (e.g., `/data`) for read-only reference materials or large datasets.
* `mode`: Optional mount mode, either `rw` (read-write, default) or `ro` (read-only).

You can also specify multiple mounts by separating them with commas (`,`):

```bash theme={null}
export SANDBOX_VOLUMES=/path1:/workspace/path1,/path2:/workspace/path2:ro
```

Examples:

```bash theme={null}
# Linux and Mac Example - Writable workspace
export SANDBOX_VOLUMES=$HOME/OpenHands:/workspace:rw

# WSL on Windows Example - Writable workspace
export SANDBOX_VOLUMES=/mnt/c/dev/OpenHands:/workspace:rw

# Read-only reference code example
export SANDBOX_VOLUMES=/path/to/reference/code:/data:ro

# Multiple mounts example - Writable workspace with read-only reference data
export SANDBOX_VOLUMES=$HOME/projects:/workspace:rw,/path/to/large/dataset:/data:ro
```

### Using WORKSPACE\_\* variables (Deprecated)

> **Note:** This method is deprecated and will be removed in a future version. Please use `SANDBOX_VOLUMES` instead.

1. Set `WORKSPACE_BASE`:

   ```bash theme={null}
   export WORKSPACE_BASE=/path/to/your/code
   ```

2. Add the following options to the `docker run` command:

   ```bash theme={null}
   docker run # ...
       -e SANDBOX_USER_ID=$(id -u) \
       -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
       -v $WORKSPACE_BASE:/opt/workspace_base \
       # ...
   ```

Be careful! There's nothing stopping the OpenHands agent from deleting or modifying
any files that are mounted into its workspace.

The `-e SANDBOX_USER_ID=$(id -u)` is passed to the Docker command to ensure the sandbox user matches the host user’s
permissions. This prevents the agent from creating root-owned files in the mounted workspace.

## Hardened Docker Installation

When deploying OpenHands in environments where security is a priority, you should consider implementing a hardened
Docker configuration. This section provides recommendations for securing your OpenHands Docker deployment beyond the default configuration.

### Security Considerations

The default Docker configuration in the README is designed for ease of use on a local development machine. If you're
running on a public network (e.g. airport WiFi), you should implement additional security measures.

### Network Binding Security

By default, OpenHands binds to all network interfaces (`0.0.0.0`), which can expose your instance to all networks the
host is connected to. For a more secure setup:

1. **Restrict Network Binding**: Use the `runtime_binding_address` configuration to restrict which network interfaces OpenHands listens on:

   ```bash theme={null}
   docker run # ...
       -e SANDBOX_RUNTIME_BINDING_ADDRESS=127.0.0.1 \
       # ...
   ```

   This configuration ensures OpenHands only listens on the loopback interface (`127.0.0.1`), making it accessible only from the local machine.

2. **Secure Port Binding**: Modify the `-p` flag to bind only to localhost instead of all interfaces:

   ```bash theme={null}
   docker run # ... \
       -p 127.0.0.1:3000:3000 \
   ```

   This ensures that the OpenHands web interface is only accessible from the local machine, not from other machines on the network.

### Network Isolation

Use Docker's network features to isolate OpenHands:

```bash theme={null}
# Create an isolated network
docker network create openhands-network

# Run OpenHands in the isolated network
docker run # ... \
    --network openhands-network \
```

<Note>
  **Docker Desktop Required**: Network isolation features, including custom networks and `host.docker.internal` routing, require Docker Desktop. Docker Engine alone does not support these features on localhost across custom networks. If you're using Docker Engine without Docker Desktop, network isolation may not work as expected.
</Note>

### Sidecar Containers

If you want to run sidecar containers to the sandbox 'runner' containers without exposing the sandbox containers to the host network, you can use the `SANDBOX_ADDITIONAL_NETWORKS` environment variable to specify additional Docker network names that should be added to the sandbox containers.

```bash theme={null}
docker network create openhands-sccache

docker run -d \
  --hostname openhandsredis \
  --network openhands-sccache \
  redis

docker run # ...
    -e SANDBOX_ADDITIONAL_NETWORKS='["openhands-sccache"]' \
    # ...
```

Then all sandbox instances will have to access a shared redis instance at `openhandsredis:6379`.

#### Docker Compose gotcha

Note that Docker Compose adds a prefix (a scope) by default to created networks, which is not taken into account by the additional networks config. Therefore when using docker compose you have to either:

* specify a network name via the `name` field to remove the scoping ([https://docs.docker.com/reference/compose-file/networks/#name](https://docs.docker.com/reference/compose-file/networks/#name))
* or provide the scope within the given config (e.g. `SANDBOX_ADDITIONAL_NETWORKS: '["myscope_openhands-sccache"]'` where `myscope` is the docker-compose assigned prefix).
