Skip to content
Guides · Coding agents

Run OpenHands in a Cloud VM with Its UI on an HTTPS URL

Updated October 27, 2026 .md

Short answer: Create a Sandboxer VM, run OpenHands' own docker run command inside it (Docker is preinstalled and the socket mount stays inside your VM), then sbx host 3000 for a private HTTPS link. In one test run on October 27, 2026, the UI answered about 40 seconds after sbx new, on the default size.

At a glance#

Topic What we measured (single run, October 27, 2026)
OpenHands version docker.openhands.dev/openhands/openhands:1.8 (API reports 1.8.0), agent server 1.26.0-python
Size used default: 4 vCPU, 8 GB RAM, 50 GB disk, $0.036/hour. OpenHands asks for at least 4 GB RAM
Time to a working UI 3.2 s sbx new + 24 s image pull and start + 12 s until / returned 200
Memory with the UI idle 810 MB used of 7.9 GB
Disk 1.29 GB app image, plus the 3.73 GB agent-server image OpenHands pulls on its own; root disk went from 5.5 GB to 11 GB used
URL https://<subdomain>-3000.box.sandboxer.com, private with a token by default
After stop and resume Same container, same PID, UI answering again (memory restores only on a machine with the same CPU type; see step 4)

We did not have an LLM key, so we didn't run an agent task. Everything below is the sandbox side: install, start, host, reach the UI and its API, stop and resume.

Why run it in a VM#

OpenHands' Docker setup mounts /var/run/docker.sock so the app can start the containers its agents work in. On your laptop that gives the app control of your Docker daemon. In a Sandboxer sandbox, the daemon belongs to that VM: Docker is preinstalled, the default user is in the docker group, and the socket only reaches containers inside the VM. Delete the sandbox and everything the agent made goes with it.

1. Create the VM#

sbx new --name openhands --type default --ttl 7200 --no-env
{"event":"ready","id":"sb_pdv3gf22hp","state":"ready",…,"url":"https://zealous-serene-atlas.box.sandboxer.com",…}
real    0m3.190s

--no-env keeps your account's secrets out of the VM. You'll paste your LLM key into the OpenHands UI later. --ttl 7200 gives it two hours before auto-stop instead of one.

Check Docker and resources:

sbx exec sb_pdv3gf22hp "docker version --format {{.Server.Version}}; id; nproc; free -g | head -2"
29.9.0
uid=1000(user) gid=1000(user) groups=1000(user),27(sudo),993(docker),995(kvm)
4
               total        used        free      shared  buff/cache   available
Mem:               7           0           6           0           0           7

2. Start OpenHands with its own Docker command#

This is the docker run from OpenHands' local setup docs. We made one change: -d instead of -it --rm, so it runs in the background. The docs also offer uv tool install openhands --python 3.12 and openhands serve.

sbx exec sb_pdv3gf22hp --timeout 600 "docker run -d --pull=always \
  -e AGENT_SERVER_IMAGE_REPOSITORY=ghcr.io/openhands/agent-server \
  -e AGENT_SERVER_IMAGE_TAG=1.26.0-python \
  -e LOG_ALL_EVENTS=true \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v ~/.openhands:/.openhands \
  -p 3000:3000 \
  --add-host host.docker.internal:host-gateway \
  --name openhands-app \
  docker.openhands.dev/openhands/openhands:1.8"
1.8: Pulling from openhands/openhands
…
Status: Downloaded newer image for docker.openhands.dev/openhands/openhands:1.8
c1ccc2162e2a6c991629f66f6dfad69e09c17eaa329bb5e67c878794e4e2929f
real    0m24.112s

Pass --timeout. Our first try without it was cut off at 30 seconds, mid-pull, before the container existed. The image tags change with each release, so copy the current command from OpenHands' docs.

Wait until it answers:

sbx exec sb_pdv3gf22hp --timeout 300 'until curl -s -o /dev/null -w "%{http_code}" localhost:3000 | grep -q 200; do sleep 1; done; docker logs openhands-app 2>&1 | tail -3'
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:3000 (Press CTRL+C to quit)
INFO:     172.17.0.1:44826 - "GET / HTTP/1.1" 200 OK

That took 12 seconds after the container started. While it ran, OpenHands also pulled the 3.73 GB agent-server image in the background.

3. Put the UI on an HTTPS URL#

OpenHands listens on 0.0.0.0:3000, so plain sbx host works. Keep it private: anyone with the UI can run commands in the VM.

sbx host sb_pdv3gf22hp 3000 --title OpenHands
{"ok":true,"type":"port.hosted","sandboxId":"sb_pdv3gf22hp","port":3000,"url":"https://zealous-serene-atlas-3000.box.sandboxer.com?_token=…","access":"private","isProtected":true,"localhost":false}

Open that URL in your browser. The first visit sets a cookie and redirects to /, so the token leaves the address bar. Here's what we saw with curl:

URL='https://zealous-serene-atlas-3000.box.sandboxer.com?_token=…'
BASE=https://zealous-serene-atlas-3000.box.sandboxer.com

curl -sS -I "$URL" | grep -i -E '^(HTTP|location|set-cookie)'
curl -sS -L -c jar -b jar -o page.html -w '%{http_code}\n' "$URL"; grep -o '<title>[^<]*</title>' page.html
curl -sS -o /dev/null -w '%{http_code}\n' "$BASE/"          # no token, no cookie
curl -sS -b jar "$BASE/health"
curl -sS -b jar "$BASE/api/v1/app-conversations/count"
curl -sS -b jar "$BASE/api/v1/settings"
HTTP/2 302
location: /
set-cookie: __sbx_auth=…; Path=/; Max-Age=2592000; HttpOnly; Secure; SameSite=Lax
200
<title>OpenHands</title>
401
"OK"
0
{"error":"Settings not found"}

The UI and its API answer through the hosted URL, and a request without the token gets 401. Settings not found means no LLM has been configured yet. In the UI, open settings, choose a provider and model, and paste your key. OpenHands keeps settings and conversations in ~/.openhands on the VM's disk, through the -v ~/.openhands:/.openhands mount.

To share the UI with a teammate, send the private URL. Use --public only for a throwaway sandbox with no keys in it.

4. Stop it and pick up later#

Stopping saves the VM's memory as well as its disk, and a stopped sandbox costs nothing for compute (its disk and memory image count toward your plan's included storage). We noted the container's PID, stopped, resumed and checked again:

sbx exec sb_pdv3gf22hp 'docker inspect -f "{{.State.Pid}} {{.State.StartedAt}}" openhands-app'
sbx stop sb_pdv3gf22hp --wait     # returns once the stop's snapshot is done
sbx resume sb_pdv3gf22hp
sbx exec sb_pdv3gf22hp 'docker inspect -f "{{.State.Pid}} {{.State.StartedAt}}" openhands-app; curl -s -o /dev/null -w "%{http_code}\n" localhost:3000/health'
691 2026-10-27T02:34:37.799958911Z
…
691 2026-10-27T02:34:37.799958911Z
200

The same container kept running, and the private URL and cookie from before the stop still worked (/health returned 200 in 0.2 s). Hosted routes and tokens are kept across stop and resume.

The exception: memory is restored only when the resume lands on a machine with the same CPU type. If none is free within 2 minutes, the sandbox boots from disk instead and shows memoryRestored: false with resumeReason: "cpu_mismatch". Your files and ~/.openhands are kept, but the container is not running, so run the same docker run again. To wait for a matching machine instead (up to 30 minutes), use sbx resume --require-memory. A resume at a new size (--type large) always boots from disk. In our test memoryRestored read null after the memory restore; it currently reads null after a resize cold boot too, so check the container (docker inspect, as above) rather than the field.

Size#

Size When
default (4 vCPU, 8 GB) What we used. The idle app used 810 MB, which leaves room for the agent's runtime container and a typical repo's build.
large (8 vCPU, 16 GB, 125 GB disk) Big repos, heavy test suites, or several OpenHands conversations running at once. It uses machine time at 2× the default rate.

You can change size later with sbx resume <id> --type large. That cold-boots, so restart the container afterwards.

FAQ#

Is it safe to mount the Docker socket into the OpenHands container here?#

The socket gives OpenHands full control of the Docker daemon. Here that daemon runs inside your own VM, not on your laptop or a shared host. The worst it can reach is that VM, and with --no-env the VM holds none of your account's secrets.

Why does the private URL return 401?#

Private hosted URLs need the _token query parameter on the first visit. That visit sets a 30-day cookie, so later requests and the UI's own API calls work without it. Open the full URL that sbx host printed, or run sbx host <id> 3000 again: it returns the same URL and token.

Did you test an agent task?#

No. We had no LLM key for this test, so we didn't start a conversation. We verified the install, the hosted UI, the /health and conversation API through the HTTPS URL, and the stop and resume. We didn't verify the agent's runtime containers starting for a task.

Can I use openhands serve instead of docker run?#

Yes. OpenHands' docs recommend uv tool install openhands --python 3.12 and then openhands serve, which checks Docker and pulls the images for you. We tested the docker run path because it needs nothing but the Docker that's already in the VM.

More guides

Top AI sandbox platforms for code execution in 2026, ranked

For running AI-written code we rank Sandboxer, Freestyle and E2B first: each gives code its own VM with an API or SDK and can pause with memory. Pick Daytona for Windows or GPUs, Modal or Northflank for GPUs at scale, E2B or Northflank to run in your own cloud, and Vercel Sandbox if your app lives on Vercel.

Read the guide
Best sandboxes for running coding agents (Claude Code, Codex, Gemini CLI) in 2026, ranked

For coding agents we rank Sandboxer first: a full Ubuntu VM with Claude Code and Codex preinstalled, Docker, and stop-and-resume that keeps the agent's session in memory. Freestyle and Amp Orbs also keep memory across pauses. Pick E2B for prebuilt agent templates on open source, Docker Sandboxes for free local runs, and Codespaces if you live in GitHub.

Read the guide
Best Daytona sandbox alternatives in 2026, ranked

The best Daytona alternatives depend on why you're switching. For a full Linux microVM on every sandbox with memory-saving stop and Docker, we rank Sandboxer first. E2B suits open source and self-hosting, Modal massive short-job fleets, Northflank bring-your-own-cloud with GPUs, and Vercel Sandbox apps on Vercel.

Read the guide
Best E2B alternatives in 2026, ranked

If you're leaving E2B for longer sessions or a fuller machine, we rank Sandboxer first, then Freestyle: both give each sandbox a full Linux VM that keeps memory across pauses, with Docker and no short session cap. Pick Daytona for Windows or GPUs, Northflank for bring-your-own-cloud, and stay on E2B if you need open source.

Read the guide