AI Coding AgentsDockerSelf-Hosting
OpenHands with Docker: a self-hosted AI coding agent with a local model (Linux, Windows, Mac)
Before you start
- 20 min read
Boxes marked Run in terminal are what you type; plain text explains why. Check what you need first

What you get in one minute#
OpenHands is a free, open-source AI coding agent with a web page: you describe a task, and the agent edits files, runs shell commands and shows its work, all inside one Docker container on your own computer.

Logo: the official OpenHands project (github.com/OpenHands/OpenHands)
The project now calls the web interface Agent Canvas and marks the old "local GUI" as legacy. This guide follows the current Docker route. The agent only sees the folders you mount, and the model can be a local one served by Ollama (see our Ollama guide), so your code need not leave your machine.
| What | Value (official docs, read October 2026) |
|---|---|
| Current version | Agent Canvas / OpenHands v1.34.0, released October 2026 (latest) |
| Image to pin | ghcr.io/openhands/agent-canvas:1.34.0 (tag checked on the registry; Linux amd64 and arm64) |
| Time needed | About 20 minutes without the model download (our estimate, not measured) |
| Size and RAM | Not documented for the container. The docs call a VM with 2 vCPU and 4 GB RAM enough for one user |
| Local model hardware | The docs name 24 GB VRAM, or a Mac with 64 GB memory, for their recommended model |
| Ports | TCP 8000 on your computer only (127.0.0.1); the page is at /canvas |
| Licence | MIT (LICENSE and package.json in the repository) |
| Official docs | docs.openhands.dev and github.com/OpenHands/OpenHands |
At a glance:
- What it is: a browser page plus an agent server in one container, on Linux, Windows or Mac (Docker Desktop).
- The Docker socket: the current image does not mount it. The legacy app did, and one docs example still shows it (see below).
- Local models: the docs recommend Qwen3.6-35B-A3B, which needs serious hardware. Small models often act like a plain chatbot.
- Privacy: the first setup screen defaults to a hosted model. Choose a local endpoint to keep prompts and code on your machine.
- Honest limit: the agent can run any shell command inside its container. Treat it like a new colleague with a keyboard.
How it fits together#
Your browser talks to one container on 127.0.0.1:8000. The container reaches the model, and only two folders are shared with it.
Drawn for this guide from the official Docker docs. The dashed arrow is optional and is the one that leaves your machine.
Before you start#
You need Docker with Compose and a browser. First, the ways to run it, so you see why this guide picks Docker:
| Method | Agent can reach | Our view |
|---|---|---|
| Docker, one container (this guide) | Only the mounted folders | Start here |
| Docker, one container per conversation | Each conversation's workspace | Optional, Step 6 |
npm install -g @openhands/agent-canvas or npx | Your whole user account | The docs warn: "full access to your filesystem" |
| Desktop app (preview build) | Your whole user account | Early preview, not covered |
Linux: Docker Engine with the Compose plugin, curl, an x86_64 or arm64 machine.
docker --version docker compose version
Windows: Docker Desktop for Windows, started, with PowerShell.
docker --version docker compose version
Mac: Docker Desktop for Mac (Apple silicon or Intel), started, with Terminal.
docker --version docker compose version
Checklist:
- [ ] Docker running (
docker psshows a table, not an error) - [ ] Port 8000 free on your computer
- [ ] A model plan: local Ollama or a hosted provider key
- [ ] For the HTTPS section only: a domain with a DNS record and ports 80 and 443 free
Tested by DIY Lab Hub: not yet. The commands come from the official README at the v1.34.0 tag and the docs pages read in October 2026. The Compose file is our translation of the official docker run command. We did not run it.
Step 1: Create the folders#
Everything lives under ~/docker_volumes/openhands. The projects folder is the only part of your disk the agent will see.
Linux#
mkdir -p ~/docker_volumes/openhands/projects cd ~/docker_volumes/openhands
Windows (PowerShell)#
New-Item -ItemType Directory -Force -Path "$HOME\docker_volumes\openhands\projects" | Out-Null Set-Location "$HOME\docker_volumes\openhands"
Mac (Terminal)#
Same commands as Linux:
mkdir -p ~/docker_volumes/openhands/projects cd ~/docker_volumes/openhands
Check it worked. ls -d ~/docker_volumes/openhands/projects (Linux, Mac) or Test-Path "$HOME\docker_volumes\openhands\projects" (Windows, prints True).
Tip: Put only the projects you are happy to hand over in this folder. Never your home folder, never a folder with
.envfiles, SSH keys or password exports. The agent can read everything in it.
Step 2: Write the Compose file and start OpenHands#
The official command is one docker run; this Compose file maps its flags one to one (pinned image, port on 127.0.0.1 only, /projects mount, settings volume). Settings go in a named Docker volume, not in ~/docker_volumes, because the docs warn that a host folder there can cause unable to open database file on Linux (the container user is UID 10001). extra_hosts is the docs' --add-host host.docker.internal:host-gateway, needed in Step 4. AGENT_CANVAS_DISABLE_TELEMETRY=1 is the documented telemetry switch.
Linux#
cd ~/docker_volumes/openhands
cat > docker-compose.yml << 'EOF'
services:
openhands:
image: ghcr.io/openhands/agent-canvas:1.34.0
container_name: openhands
restart: unless-stopped
tty: true
stdin_open: true
ports:
- "127.0.0.1:8000:8000"
environment:
- AGENT_CANVAS_ALLOW_LAN_SESSION_KEY=true
- AGENT_CANVAS_DISABLE_TELEMETRY=1
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- openhands-data:/home/openhands/.openhands
- ./projects:/projects
volumes:
openhands-data:
name: openhands-data
EOF
docker compose up -d
docker compose ps
docker compose logs --tail=50 openhands
Windows (PowerShell)#
Create the same file with an editor, then start it. Save it as UTF-8:
Set-Location "$HOME\docker_volumes\openhands" notepad docker-compose.yml
Paste the YAML from the Linux block into Notepad and save. Then:
docker compose up -d docker compose ps docker compose logs --tail=50 openhands
Mac (Terminal)#
Same commands as Linux (the cat > docker-compose.yml block, then docker compose up -d).
Check it worked. docker compose ps shows openhands as running. The docs publish no expected log text for this image, so read the log for errors rather than for a specific line. Then test the page:
curl -I http://localhost:8000/canvas
On Windows use curl.exe -I http://localhost:8000/canvas. You should get an HTTP status line, not "connection refused".
Tip:
AGENT_CANVAS_ALLOW_LAN_SESSION_KEY=truelets the page log itself in without a key. That is only safe because the port is published on127.0.0.1. The README says to omit it whenever you publish the port on a network, as the HTTPS section does.
Step 3: Open the page and finish first-time setup#
Linux#
xdg-open http://localhost:8000/canvas
Windows (PowerShell)#
Start-Process "http://localhost:8000/canvas"
Mac (Terminal)#
open http://localhost:8000/canvas
The wizard asks you to choose an agent, check the backend, set up the LLM and start a workflow. Choose the OpenHands agent. The backend step shows "You're connected!" for 127.0.0.1:8000. At the LLM step do not accept the default if you want to stay local: it is the hosted OpenHands service. Do Step 4, or use Settings > LLM later.
Check it worked. The backend shows as connected.
Step 4: Connect a local model with Ollama#
The container must reach Ollama as host.docker.internal, so Ollama listens on all interfaces. The docs also set a large context, because "the default (4096) is way too small - not even the system prompt will fit". For installing Ollama, see our Ollama guide.
The docs recommend Qwen3.6-35B-A3B, an open-weight model built for agentic coding. They say quantised builds need a GPU with at least 24 GB of VRAM, or an Apple Silicon Mac with at least 64 GB of unified memory.
Linux#
If Ollama already runs as a service, set the same variables on that service first (the Ollama guide shows how). Otherwise:
OLLAMA_CONTEXT_LENGTH=32768 OLLAMA_HOST=0.0.0.0:11434 OLLAMA_KEEP_ALIVE=-1 nohup ollama serve & ollama pull qwen3.6:35b-a3b
Windows (PowerShell)#
The docs show only the Linux and Mac line. This is our translation of it (not run). Quit the Ollama tray app first, then in one window:
$env:OLLAMA_CONTEXT_LENGTH = "32768" $env:OLLAMA_HOST = "0.0.0.0:11434" $env:OLLAMA_KEEP_ALIVE = "-1" ollama serve
In a second window:
ollama pull qwen3.6:35b-a3b
Mac (Terminal)#
Same commands as Linux:
OLLAMA_CONTEXT_LENGTH=32768 OLLAMA_HOST=0.0.0.0:11434 OLLAMA_KEEP_ALIVE=-1 nohup ollama serve & ollama pull qwen3.6:35b-a3b
Now tell OpenHands. In the page open Settings > LLM > Advanced and enter:
| Field | Value |
|---|---|
| Custom Model | openai/qwen3.6:35b-a3b (the prefix openai/ plus the model name Ollama serves) |
| Base URL | http://host.docker.internal:11434/v1 |
| API Key | any placeholder, for example local-llm (Ollama does not check it) |
Save, start a new conversation and say hello.
Check it worked. On your computer, curl http://127.0.0.1:11434/v1/models lists the model (Windows: curl.exe). In OpenHands, a short message gets an answer. The docs also check from inside the container with docker exec <container> curl -s http://host.docker.internal:11434/v1/models (their example uses the legacy container; we did not confirm curl is in this image).
Tip:
OLLAMA_HOST=0.0.0.0makes Ollama answer other devices on your network too, and it has no login. Allow port 11434 only from your own machine in your firewall, or keep the computer on a network you trust.
For weaker hardware the docs name two community-reported models, qwen2.5-coder-14b-instruct and qwopus3.5-27b-v3 Q8_0. We did not verify matching Ollama tags, and the docs give no hardware figures for them. The other option is a hosted model; set spending limits.
Step 5: Run a first task in a safe folder#
Make a throwaway project and give the agent a small job.
Linux#
mkdir -p ~/docker_volumes/openhands/projects/hello
Windows (PowerShell)#
New-Item -ItemType Directory -Force -Path "$HOME\docker_volumes\openhands\projects\hello" | Out-Null
Mac (Terminal)#
Same command as Linux:
mkdir -p ~/docker_volumes/openhands/projects/hello
In the page choose Open Workspace and pick /projects/hello before you start the conversation. Then ask: "Create hello.py that prints hello, and run it."
Check it worked. hello.py appears in the folder on your computer, outside the container:
ls ~/docker_volumes/openhands/projects/hello
On Windows: Get-ChildItem "$HOME\docker_volumes\openhands\projects\hello". If the agent cannot write on Linux, the folder owner may not match the container user (UID 10001). The docs mention that UID only for the settings folder, so this is our guess, not a documented fix.
Tip: Always use Open Workspace first. A conversation started without it works in a folder inside the container that is not saved when the container is recreated (open issues 18960 and 19019).
Step 6 (optional): One container per conversation#
The second Docker mode, new in v1.34.0: Agent Canvas runs on your computer and each conversation gets its own hardened container. It needs Node.js 24 or later, uv and a user who may run docker, so read the next section first. Stop the all-in-one container to free port 8000: docker compose down.
Linux#
node --version uv --version npm install -g @openhands/agent-canvas OH_CONVERSATION_RUNTIME=docker agent-canvas
Then open http://localhost:8000, not /canvas.
Windows (PowerShell)#
Not supported natively ("uses POSIX user/group IDs", says the README). Use Linux under WSL 2 with Docker Desktop's WSL integration, install Node.js 24 and uv inside it, check docker info, and run the Linux commands there.
Mac (Terminal)#
Same commands as Linux, with Docker Desktop running:
npm install -g @openhands/agent-canvas OH_CONVERSATION_RUNTIME=docker agent-canvas
Check it worked. After you start a conversation, docker ps --filter name=agent-server-conversation- lists its container. Ask the agent to run id and pwd: the docs expect /workspace as the working directory.
Each container defaults to 4 GB memory and 2 CPUs and stops after 20 minutes idle. In this mode the launcher listens on all interfaces and does not auto-login, so use your firewall and the API key. Issue 19066 (open) reports the page may not update live until you reload it.
The Docker socket and the sandbox: what the risk is#
The Docker socket (/var/run/docker.sock) is the control line to the Docker daemon. Docker's own security page says only trusted users should control the daemon, because anyone who does can start a container with your host's / mounted and change your host files without restriction. Handing the socket to an AI agent therefore hands it your computer.
| Setup | Socket? | What the agent can reach |
|---|---|---|
| This guide: one container | No | /projects, the settings volume, the container itself, the network the container can use |
This guide with --privileged (docs: "Let the Agent Use Docker") | No, but broad kernel access | The docs say it "substantially weakens the isolation"; they offer "no safer middle ground" |
| Step 6: container per conversation | Host Docker used by agent-canvas | The agent runs in a container with all capabilities dropped, no-new-privileges, host UID and API on 127.0.0.1; the outer process runs as you and can use Docker |
Legacy app (openhands:1.8) | Yes, -v /var/run/docker.sock:/var/run/docker.sock | Still shown in the local-LLM page of the docs. Do not copy it |
Use the first row. The docs describe no limit on the container's outgoing network, so assume the agent can reach the internet and services such as Ollama.
Put it behind HTTPS (with or without Traefik)#
This section is for a server with a domain, or a home name you want a padlock on. With only localhost, skip it. The agent runs shell commands, so the docs ask for a firewall and an API key before you expose it. The commands run on the machine that hosts OpenHands; Windows and Mac users only need a browser.
Two changes in both routes. Remove the published port and AGENT_CANVAS_ALLOW_LAN_SESSION_KEY (with the key injected, anyone reaching the page is logged in), and set a strong LOCAL_BACKEND_API_KEY, which the page then asks for. The docs generate one with openssl rand -base64 32.
cd ~/docker_volumes/openhands docker network create proxy printf 'LOCAL_BACKEND_API_KEY=%s\n' "$(openssl rand -base64 32)" > .env chmod 600 .env
If the network already exists, that is fine. Copy the key from .env into a password manager.
With Traefik#
On a server that already runs Traefik v3 with the Docker provider, replace the Compose file with this one. It assumes an external network named proxy and an entrypoint named https; use yours.
services:
openhands:
image: ghcr.io/openhands/agent-canvas:1.34.0
container_name: openhands
restart: unless-stopped
tty: true
stdin_open: true
environment:
- AGENT_CANVAS_DISABLE_TELEMETRY=1
- LOCAL_BACKEND_API_KEY=${LOCAL_BACKEND_API_KEY}
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- openhands-data:/home/openhands/.openhands
- ./projects:/projects
networks:
- proxy
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.http.routers.openhands.rule=Host(`openhands.<your-domain>`)"
- "traefik.http.routers.openhands.entrypoints=https"
- "traefik.http.routers.openhands.tls=true"
- "traefik.http.services.openhands.loadbalancer.server.port=8000"
volumes:
openhands-data:
name: openhands-data
networks:
proxy:
external: true
Run docker compose up -d. Check it worked. curl -I https://openhands.<your-domain>/canvas returns an HTTP status line over HTTPS, and the page asks for the API key.
Without Traefik: Caddy#
Choose this if you have no Traefik. Caddy gets and renews its own certificates. Two cases:
| Case | What you do |
|---|---|
| Public domain | A DNS A record to the server, ports 80 and 443 open. Caddy gets a Let's Encrypt certificate itself |
| Home only, no domain | Use tls internal (Caddy's own local certificate) and trust Caddy's root certificate on each device |
Use the same Compose file as in the Traefik route, but delete the labels: block. Then create the Caddy folder and file:
mkdir -p ~/docker_volumes/caddy/{data,config}
cd ~/docker_volumes/caddy
Save as ~/docker_volumes/caddy/docker-compose.yml (caddy:2.11.7 is the latest Caddy release read in October 2026):
services:
caddy:
image: caddy:2.11.7
container_name: caddy
restart: unless-stopped
ports:
- "80:80/tcp"
- "443:443/tcp"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./data:/data
- ./config:/config
networks:
- proxy
networks:
proxy:
external: true
Save as ~/docker_volumes/caddy/Caddyfile. The remote_ip lines follow the docs' advice to restrict 443 to your own address; replace the placeholder, or drop those two lines at home:
openhands.example.com {
@outside not remote_ip <your-public-ip>
respond @outside 403
reverse_proxy openhands:8000
}
Home-only variant:
openhands.home.arpa {
tls internal
reverse_proxy openhands:8000
}
Start both stacks:
cd ~/docker_volumes/caddy && docker compose up -d cd ~/docker_volumes/openhands && docker compose up -d
For tls internal, install Caddy's root certificate on each device you browse from. Find it, copy it out, and import it (the OS steps are not from the OpenHands or Caddy docs: Windows "Trusted Root Certification Authorities", macOS Keychain Access with "Always Trust", Linux your distribution's CA store):
docker exec caddy find /data -name root.crt docker cp caddy:<path-from-find> ./caddy-root.crt
Check it worked. curl -I https://openhands.example.com/canvas returns an HTTP status line over HTTPS. For a home name the browser shows a padlock only after the root is trusted.
Tip: The Canvas page is under
/canvas, so the address ishttps://openhands.<your-domain>/canvas. The bare domain may show nothing useful.
Security and testing#
| Control | How |
|---|---|
| Where the port listens | 127.0.0.1:8000 in Step 2. Never 8000:8000 on a machine on a network |
| API key | Required once the port is reachable by others: LOCAL_BACKEND_API_KEY in .env, chmod 600 |
| Firewall | Only 22, 80 and 443 open, per the docs' VM guide; 8000, 18000, 18001 and 3001 stay closed |
| Shared editor origin | Issue 16492 (listed in the docs): the bundled editor shares the page's origin and could read stored session keys. Open no untrusted content there |
Quick tests (Linux, Mac; same in PowerShell):
cd ~/docker_volumes/openhands
docker compose ps
docker compose logs --tail=100 openhands
docker inspect openhands --format '{{json .Mounts}}'
The last line should list only the settings volume and /projects, and no docker.sock.
What leaves your machine#
| Data | Goes where |
|---|---|
| Your prompts, file contents the agent reads, command output | To the model you chose. With Ollama on your computer, nowhere. With a hosted provider or the default hosted OpenHands model, to that provider |
| Claude Code, Codex or Gemini CLI used through ACP | To those vendors, using their own login |
| Product telemetry | Off with AGENT_CANVAS_DISABLE_TELEMETRY=1. The pages read do not say what it contains |
Common mistakes#
| Mistake | Why it happens | Do this instead |
|---|---|---|
| Starting a conversation without choosing a workspace | The agent then works in a folder inside the container. Issues 18960 and 19019 (both open) report the files vanish when the container is recreated | Use Open Workspace and pick /projects/<name> first |
Binding a host folder to ~/.openhands on Linux | The container user is UID 10001; the docs warn of unable to open database file | Use the named volume, as in Step 2 |
127.0.0.1 as the model address | Inside the container that means the container itself | http://host.docker.internal:11434/v1, with extra_hosts on Linux |
| Leaving Ollama at its default context | The docs say 4096 is too small even for the system prompt | Set OLLAMA_CONTEXT_LENGTH=32768 |
| Using a small model and blaming OpenHands | The docs say a weak model can act like a plain chatbot or fail tool calls | Try the recommended or a community-reported model before debugging the setup |
Model name without the openai/ prefix | The error is LLM Provider NOT provided | openai/<served-model-id> for Ollama, LM Studio, vLLM and SGLang |
| Publishing port 8000 on every interface | The page can log itself in when the session key is injected | Keep 127.0.0.1:8000; behind HTTPS drop AGENT_CANVAS_ALLOW_LAN_SESSION_KEY, set LOCAL_BACKEND_API_KEY |
Adding --privileged so the agent can run Docker | It is the documented way, but it weakens the isolation | Add it only when needed, on a machine you can afford to lose |
Running latest after a broken image publish | The docs' crash-loop page describes ERR_MODULE_NOT_FOUND from a bad latest | Pin 1.34.0, and pin an older tag such as 1.26.0 if a new one fails |
| AI assistants: giving the old commands | Older guides and answers built on them show the legacy app: image docker.openhands.dev/openhands/openhands:1.8, port 3000, the docker.sock mount, or openhands serve. The docs now mark it "Local GUI (Legacy)" | Use ghcr.io/openhands/agent-canvas:1.34.0, port 8000, page /canvas |
AI assistants: a model name like ollama/qwen3.6:35b-a3b | The ollama/ prefix is common in other tools | This setup uses openai/qwen3.6:35b-a3b and the /v1 base URL |
Tip: Before you paste any OpenHands command from a forum or an AI chat, look for
docker.sockand port 3000. Both mean the old app, and the socket is the part you do not want to hand over.
Tip: Test a new model on one small task in the
hellofolder before a real repository. If it only chats, it will not edit files.
Troubleshooting#
| Problem | Solution |
|---|---|
port is already allocated or port 8000 busy | Change the Compose port to "127.0.0.1:3000:8000" and open http://localhost:3000/canvas |
Container restarts in a loop with Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/opt/agent-canvas/<name>.mjs' | The image was published broken (docs). Pin an earlier tag such as 1.26.0, then update once a fix is out |
| Page loads but "backend disconnected" or wrong key | Check Manage Backends. The generated key: docker exec openhands sh -c 'cat "$STATE_DIR/api-key.txt"' (README) |
LLM Provider NOT provided | Use openai/<model> in Settings > LLM > Advanced and check the Base URL |
| Model cannot be reached | The URL must work from the container: host.docker.internal, Ollama on 0.0.0.0, extra_hosts on Linux |
| The agent only chats, ignores files | Context too small or model too weak for tools. Raise the context, then change the model |
error creating default "bridge" network: operation not permitted | The agent tried to start containers. By default the container has no Docker daemon. See the socket section before using --privileged |
Terminal fails with TmuxObjectDoesNotExist | Issue 18982 (open): the agent server runs without a UTF-8 locale. The issue's analysis points at LANG and LC_ALL; setting a UTF-8 value is our reading, not a documented fix |
502 Could not create conversation container in Step 6 | Issue 18584 (open): the per-conversation mode fails on a rootless Docker daemon. Use the all-in-one container or a rootful daemon |
Known bugs (open, October 2026)#
- 18960, 19019: files outside
/projectsare lost when the container is recreated. - 19066: per-conversation mode may not update the page until you reload.
- 18847: after connecting GitHub, the sandboxed agent reported no credentials and could not push.
- 18584, 18982: rootless Docker in Step 6; terminal error without a UTF-8 locale.
Diagnostics: docker compose ps, docker compose logs --tail=200 openhands, docker inspect openhands, docker stats openhands.
Updates and backups#
Update. Read the release notes, change the tag in docker-compose.yml, then:
cd ~/docker_volumes/openhands docker compose pull docker compose up -d docker compose logs --tail=100 openhands
Recreating the container drops everything outside /projects and the settings volume.
Back up. The settings volume holds your settings, secrets and conversation history. Stop the container, archive the volume and your projects, and start again. The archive holds secrets, so chmod 600:
cd ~/docker_volumes/openhands docker compose down mkdir -p backups docker run --rm -v openhands-data:/data:ro -v "$PWD/backups:/backup" alpine:3 \ tar -czf "/backup/openhands-data-$(date +%F).tar.gz" -C /data . tar -czf "backups/openhands-projects-$(date +%F).tar.gz" projects chmod 600 backups/*.tar.gz docker compose up -d
On Windows, use PowerShell with -v "${PWD}\backups:/backup" and "/backup/openhands-data-$(Get-Date -Format yyyy-MM-dd).tar.gz"; Windows 10 and 11 ship tar for the projects. On Mac use the Linux commands.
Schedule. Linux and Mac: a crontab entry at 03:00 that runs the same lines. Windows: a Task Scheduler task that runs a .ps1 file with them. Keep a copy off the machine.
Restore test. Unpack into a new empty folder, never over the live one:
mkdir -p /tmp/restore-test && tar -xzf backups/openhands-data-<date>.tar.gz -C /tmp/restore-test ls /tmp/restore-test
Performance and resources#
The docs publish no RAM, CPU or disk figures for the container. They call a VM with 2 vCPU and 4 GB RAM enough for one user. The model is what costs: the recommended one needs 24 GB of VRAM or a 64 GB Apple Silicon Mac.
- Measure:
docker stats openhandsfor the container,ollama psfor the model. - Keep the model loaded:
OLLAMA_KEEP_ALIVE=-1(from the docs) avoids reload waits. - Step 6 limits:
OH_CONVERSATION_CONTAINER_MEMORY(default 4g),OH_CONVERSATION_CONTAINER_CPUS(2.0),OH_CONVERSATION_CONTAINER_PIDS_LIMIT(512). A client can ask for more, so they are no hard cap on a shared server.
FAQ#
Is OpenHands free? The software is MIT licensed. A hosted model costs money, because OpenHands sends many prompts. A local model costs only hardware and power.
Is it the same as "Agent Canvas"? Yes. The repository now ships the Agent Canvas interface, which runs the OpenHands agent. It can also drive Claude Code, Codex, Gemini CLI, Pi and OpenCode through ACP, using their own logins.
Does it need a GPU? The agent does not. A good local model does: 24 GB of VRAM or a 64 GB Mac for the recommended one.
Is the Docker route safe? Safer than running it on your whole account, not risk-free. The agent can run any command in the container and read all of /projects. Keep the mount small, the port on 127.0.0.1, skip --privileged and never mount the Docker socket.
Does it work offline? The container and a local Ollama model need no cloud account. You need internet once, to pull the image and the model.
Sources#
- OpenHands repository README at v1.34.0, README.windows.md, docs/SELF_HOSTING.md, LICENSE and release v1.34.0 - read October 2026
- Install Agent Canvas, Use Docker with Agent Canvas, one Docker container per conversation, VM / self-hosted, overview, architecture, first-time setup and troubleshooting - read October 2026
- Run local LLMs with OpenHands, LLM overview and recommendations and Configure a model - read October 2026
- Image
ghcr.io/openhands/agent-canvas(tag1.34.0checked on the registry, amd64 and arm64) - October 2026 - Docker Engine security, Caddy v2.11.7 and Caddy request matchers - read October 2026
- GitHub issues #16492, #18584, #18847, #18960, #18982, #19019, #19066 - read October 2026
Checked against the official docs on 2026-10-30.