OpenHands
Overview
OpenHands is a popular open-source AI software development agent. It works like an autonomous developer: you describe a task in plain language, and the agent plans the work, edits files, runs commands and reads documentation inside a sandboxed environment that it creates and controls for itself.
This SecureAnyCloud image installs Docker CE from the official Docker repository and runs the OpenHands control plane as a container, managed by Docker with a restart policy. The container is bound to the loopback connector 127.0.0.1:3000 behind an nginx reverse proxy on port 80, and it mounts the host Docker socket so it can launch a fresh, isolated runtime container for each conversation.
OpenHands has no login of its own, so nginx protects the whole app with HTTP Basic Auth, using a unique password generated on the first boot of every VM. No model key is baked into the image. You bring your own LLM provider key and enter it in the OpenHands Settings screen, so your provider account and data stay yours. Each boot pulls the OpenHands image fresh, so your VM is never left on a stale build.
What you get:
- OpenHands running as a container managed by Docker, pulled fresh on first boot
- Docker CE preinstalled from the official Docker apt repository, with the socket mounted so the agent can spawn per-session runtime containers
- The OpenHands agent UI on
:80, fronted by nginx with HTTP Basic Auth - A unique Basic Auth login password generated on first boot and recorded in a root-only file
- No LLM key baked in: you add your own provider key in the OpenHands Settings screen
docker.serviceandnginx.serviceas enabled, active systemd units- An unauthenticated
/healthzendpoint for Azure Load Balancer health probes - Streaming and WebSocket-friendly nginx proxy configuration for the agent event log
- 24/7 SecureAnyCloud support
Prerequisites
You need an active Azure subscription, an SSH key pair, and a VNet with a subnet in the target region.
Standard_B2ms (2 vCPU / 8 GiB RAM) is a comfortable starting size. It gives the OpenHands control plane room to run alongside a runtime container for your task.
Configure the network security group (NSG) to allow inbound 22/tcp from your management network and 80/tcp. OpenHands serves plain HTTP on port 80. For production, terminate TLS in front of it with your own domain and consider adding 443/tcp (see Maintenance).
You also need your own API key for the LLM provider you plan to use (OpenAI, Anthropic, Google Gemini and many others). You enter it inside OpenHands after you sign in.
Step 1 - Deploy from the Azure Marketplace
Sign in to the Azure Portal, choose Create a resource, search the Marketplace for OpenHands by SecureAnyCloud, and select Create.
On the Basics tab, pick your subscription, resource group, region and size. Under Administrator account, choose SSH public key and paste your key. Under Inbound port rules, allow SSH (22) and HTTP (80).
Then select Review + create and Create.
Step 2 - Deploy from the Azure CLI
# Accept the Marketplace terms once per subscription (required before the first CLI deploy)
az vm image terms accept --urn sac1647283583153:openhands-ubuntu-24-04:default:latest
az vm create \
--resource-group <your-rg> \
--name openhands \
--image sac1647283583153:openhands-ubuntu-24-04:default:latest \
--size Standard_B2ms \
--admin-username azureuser \
--ssh-key-values ~/.ssh/id_ed25519.pub \
--vnet-name <your-vnet> --subnet <your-subnet> \
--public-ip-sku Standard
az vm open-port --resource-group <your-rg> --name openhands --port 80 --priority 1010Step 3 - Connect to your VM
Connect to the VM over SSH:
ssh azureuser@<vm-public-ip>Step 4 - Confirm the services are running
Check the status of the services:
systemctl is-active docker.service nginx.service
sudo docker ps --filter name=openhands-app --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'Both systemd units report active, and Docker shows the openhands-app container Up. Docker manages the OpenHands control plane, which is bound to the loopback connector 127.0.0.1:3000. nginx fronts it on port 80 behind HTTP Basic Auth.
Step 5 - Retrieve your login credentials
The appliance's network access gate is HTTP Basic Auth (user admin). The password is generated uniquely on the first boot of your VM and written to a root-only file. Read it as root:
sudo cat /root/openhands-credentials.txtThis file contains OPENHANDS_URL, OPENHANDS_USERNAME and OPENHANDS_PASSWORD. Store the password somewhere safe. OpenHands can run code and control Docker on this VM, so this gate is what keeps the agent private to you.
Step 6 - Confirm the health endpoint
nginx serves an unauthenticated health endpoint for load balancers and probes. Query it:
curl -s http://localhost/healthzIt returns ok. This endpoint never requires authentication, so it is safe for an Azure Load Balancer health probe.
Step 7 - Confirm the login password is enforced
A password is set on first boot, so an unauthenticated request to OpenHands is rejected with HTTP 401. Nobody reaches the agent without the password:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/It prints 401. A wrong password is also rejected with 401. Only the per-VM password from Step 5 returns 200:
curl -s -o /dev/null -w '%{http_code}\n' -u 'admin:<OPENHANDS_PASSWORD>' http://127.0.0.1/This prints 200.
Step 8 - Sign in and connect your LLM provider
Browse to http://<vm-public-ip>/. Your browser first prompts for HTTP Basic Auth credentials. Enter admin and the password from Step 5.
Behind that gate, OpenHands opens an AI Provider Configuration screen on your first visit. Choose your LLM provider, pick a model and paste your own API key, then select Save. No key ships in the image, so your provider account stays yours. Your key is stored only on this VM.
Step 9 - Start building
After you save your key, you land on the Let's Start Building! home screen. Choose Open Repository to connect a GitHub, GitLab, Bitbucket or Azure DevOps account and get suggested tasks. Or choose Start from Scratch to begin a conversation that is not tied to a repository.
Describe a task. OpenHands plans it, then edits files and runs commands inside a runtime container that it launches for the session.
Step 10 - Manage your model in Settings
Open Settings from the left rail to manage the agent. The LLM tab holds your model profiles, including the provider and key you configured in Step 8. The other tabs cover the Agent, Condenser, Verification, MCP servers, Skills, Integrations, Application preferences and Secrets.
Add more model profiles here and switch between them per conversation.
Step 11 - Connect your repositories
Open Integrations in Settings to connect a Git provider. Add a GitHub, GitLab or Bitbucket token so OpenHands can read your repositories, propose changes and open pull requests as it works. Tokens are stored only on this VM.
Step 12 - Confirm the runtime model
OpenHands launches an isolated runtime container for each conversation through the host Docker socket, which the control plane container has mounted. Inspect the mount:
sudo docker inspect openhands-app --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' | grep docker.sockThe output shows /var/run/docker.sock -> /var/run/docker.sock. This mount is how the agent runs your task in a sandbox that is separate from the control plane. It is also why the nginx Basic Auth gate in front of the app matters.
Maintenance
- Edge password. The Basic Auth password in front of OpenHands is set on first boot. To change it, run
sudo sh -c 'printf "admin:%s\n" "$(openssl passwd -apr1 NEW_PASSWORD)" > /var/lib/openhands/.htpasswd' && sudo systemctl reload nginx. - LLM provider key. Your model key is entered under Settings and stored only on this VM under
/var/lib/openhands. Back up that path to preserve your configuration and conversation history. - Upgrades. OpenHands runs as the
openhands-appcontainer from the pinned stable image, and first boot pulls it fresh automatically. To upgrade an already running VM, runsudo docker pull docker.openhands.dev/openhands/openhands:1.8. Then recreate the container with the same-p 127.0.0.1:3000:3000 -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/openhands:/.openhandsbinding. - TLS. OpenHands serves plain HTTP on port 80. Front it with TLS (for example certbot with your own domain) before you enter real API keys or run it in production.
- Security patches. unattended-upgrades stays enabled, so the OS keeps receiving security updates automatically.
- License. OpenHands is MIT licensed. This image ships the open-source OpenHands. The SecureAnyCloud charge covers packaging, security patching, image maintenance and support.
Support
SecureAnyCloud provides 24/7 expert support for this image. For questions or help with your deployment, contact sales@secureanycloud.com.
Deploy on Azure
Launch OpenHands on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com
Overview
OpenHands is an open-source AI software engineering agent (OpenHands/OpenHands, MIT). You describe a task in a browser. The agent plans it, then reads and edits files, runs shell commands and browses the web to carry it out, working inside a sandboxed runtime container that it launches on demand.
This SecureAnyCloud image runs OpenHands 1.8 on Ubuntu 24.04 LTS.
What you get:
- The official OpenHands application container under Docker, bound to the loopback address
127.0.0.1:3000 - nginx on port 80 with HTTP Basic Authentication. An unauthenticated
/healthzendpoint stays open for load balancer probes, and everything else requires the password - A default security group that opens only port 22 (SSH), port 80 (HTTP) and port 443 (HTTPS), so port 3000 is never reachable from outside the instance
- A one-shot service that, on the first boot of every deployed instance, generates a fresh password unique to that instance and writes it to
/root/openhands-credentials.txt(mode0600, root only). No shared or default credential ships in the image
You supply your own model provider API key
No model API key, model credits or hosted inference endpoint ship with this image. OpenHands serves its interface immediately after launch. Before the agent can run a task, you must enter your own provider API key (for example Anthropic or OpenAI) on the AI Provider Configuration screen that opens on first visit. This first-run step is required.
Your key is stored only on your own instance, under /var/lib/openhands. Every model request goes directly from your instance to the provider you chose.
Why the whole application sits behind a password
OpenHands has no built-in login of its own. Upstream designs it to run on localhost. It also mounts the host Docker socket so it can start its sandboxed runtime containers, which makes it root-equivalent on the instance. An ungated, internet-facing instance would therefore be completely open.
The nginx Basic Authentication gate in front of the whole application keeps the agent private to you. It is the load-bearing security control on this image. Do not remove it without putting an equivalent gate in its place.
Storage layout
Two dedicated EBS volumes keep the stateful tiers off the operating system disk. Each volume is independently resizable:
Mount point Contents
/var/lib/openhands OpenHands state: settings, conversation history, the agent workspace and the nginx password file
/var/lib/docker Docker image and container store, including the agent runtime images
Both are mounted by filesystem UUID from /etc/fstab, so the layout reproduces on every instance you launch.
Prerequisites
Before you deploy, make sure you have:
- An AWS account subscribed to this product in AWS Marketplace
- An EC2 key pair in your target region for SSH access
- A security group that allows inbound TCP 22 (SSH) from your IP and TCP 80 (HTTP) from your users
- An API key from a model provider that OpenHands supports (for example Anthropic or OpenAI), which you paste in on first visit
- Recommended instance type:
m5.large. Usem5.xlargeor larger if you expect several concurrent agent conversations, because each one starts its own runtime container
Connecting to your instance
OS variant Login user Example
Ubuntu 24.04 ubuntu ssh -i your-key.pem ubuntu@<instance-public-ip>
Step 1 - Launch from the AWS Marketplace console
- Open the product page in AWS Marketplace, choose Continue to Subscribe, then choose Continue to Configuration.
- Select the OpenHands on Ubuntu 24.04 delivery option and your region, then choose Continue to Launch.
- Choose an instance type (
m5.largeor larger), your VPC/subnet, your key pair and the security group described above. Then launch the instance.
Step 2 - Launch from the AWS CLI
Run the following command to launch the instance:
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxxxxxxx \
--instance-type m5.large \
--key-name your-key \
--security-group-ids sg-xxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=openhands}]'Step 3 - Connect to your instance
Connect to the instance over SSH:
ssh -i your-key.pem ubuntu@<instance-public-ip>Step 4 - Confirm the services are running
Check the status of the services:
systemctl is-active docker.service nginx.serviceBoth report active:
active activeStep 5 - Confirm the OpenHands container
List the running containers:
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'One application container runs. This image ships OpenHands, Docker and nginx and nothing else, so there is no separate database or cache tier to operate. The output looks like this:
NAMES IMAGE STATUS openhands-app docker.openhands.dev/openhands/openhands:1.8 Up 15 minutesStep 6 - Confirm the dedicated storage volumes
Check the root volume and the two data volumes:
df -h / /var/lib/docker /var/lib/openhandsAgent state and the Docker image store are each on their own volume, separate from the operating system disk. The output looks like this:
Filesystem Size Used Avail Use% Mounted on /dev/root 29G 3.4G 25G 13% / /dev/nvme1n1 79G 11G 64G 15% /var/lib/docker /dev/nvme2n1 30G 176K 28G 1% /var/lib/openhandsStep 7 - Confirm the security gate
Request the health endpoint and the application root without a password. Run:
curl -s -o /dev/null -w 'healthz=%{http_code}\n' http://127.0.0.1/healthz
curl -s -o /dev/null -w 'unauthenticated=%{http_code}\n' http://127.0.0.1/The health endpoint is open for load balancer probes. Everything else is refused without the password:
healthz=200 unauthenticated=401Step 8 - Retrieve your instance password
Print the sign-in address and user name:
sudo grep -E '^OPENHANDS_(URL|USERNAME)=' /root/openhands-credentials.txtTo read the password itself, use one of these commands:
Purpose Command
Show the whole credentials file, password included sudo cat /root/openhands-credentials.txt
Show only the password sudo grep '^OPENHANDS_PASSWORD=' /root/openhands-credentials.txt
The user name is always admin. The password is generated on the first boot of your instance and is unique to it.
Step 9 - Open OpenHands in a browser
Browse to http://<instance-public-ip>/ and sign in as admin with the password from Step 8 when the browser prompts you.
Enter the password in the browser's sign-in prompt. Do not put it in the address bar. A URL of the form http://admin:password@<instance-public-ip>/ does log you in. However, browsers forbid a page whose address contains credentials from making fetch requests, and OpenHands loads its interface text that way. The result is a UI where every label shows a raw code such as HOME$LETS_START_BUILDING instead of English.
If you see raw codes, you signed in through the address bar. Reset the address to http://<instance-public-ip>/ and use the sign-in prompt instead.
Step 10 - Connect your model provider
On your first visit, OpenHands opens AI Provider Configuration. Choose your LLM Provider, pick an LLM Model, paste your own API Key and choose Save. The agent cannot run a task until you do.
You can change this at any time under Settings. A newly launched instance has no model profile saved, which confirms that no credential ships in the image:
Step 11 - Start a task
Choose Open Repository to point the agent at a repository, or start a conversation and describe the task in plain language.
When the conversation starts, OpenHands launches a sandboxed runtime container through the host Docker socket. The agent edits files and runs commands inside that container, so it can install packages, run tests and iterate without touching the rest of your environment.
Watch the runtime container appear while a conversation is running:
docker ps --format '{{.Names}} {{.Image}}'The first conversation takes longer to start than later ones, because the runtime image is pulled on demand if it is not already cached.
Step 12 - Extend the agent with MCP servers (optional)
OpenHands supports Model Context Protocol servers, which give the agent extra tools. A new instance starts with none configured, so you decide exactly what the agent can reach.
Operations
Change the sign-in password
Replace NEW_PASSWORD with your own value:
Step Command
Write the new password sudo sh -c 'printf "admin:%s\n" "$(openssl passwd -apr1 NEW_PASSWORD)" > /var/lib/openhands/.htpasswd'
Apply it sudo systemctl reload nginx
Restart OpenHands
sudo docker restart openhands-appView the application logs
sudo docker logs --tail 20 openhands-appBack up your state
Everything OpenHands keeps (settings, conversation history and the agent workspace) lives under /var/lib/openhands. Snapshot that EBS volume, or archive the directory:
Purpose Command
Archive the state directory sudo tar -czf openhands-state.tar.gz -C /var/lib/openhands .
Enable HTTPS
For production use, put a domain name in front of the instance and terminate TLS on port 443. Point the DNS record at your instance's public address. Then obtain a certificate with your preferred tool and configure it in /etc/nginx/sites-available/sac-openhands.
Keep the auth_basic directives in place. They are the control that keeps the agent private.
Security notes
- Treat the web interface as shell access. The agent can run arbitrary commands and controls Docker on this instance, so access to the interface is equivalent to shell access to the instance.
- Restrict the ports. Limit port 80 (and 443) in the security group to the addresses your team uses, rather than leaving them open to the internet.
- Keep the gate. Keep the per-instance password or replace it with your own, but never remove the gate without an equivalent control.
- Protect your provider key. Your model provider key is stored on the instance. Anyone with access to the interface can use it, and so can the agent.
Support
SecureAnyCloud publishes this image with 24/7 technical support by email and chat. Support covers deployment, instance sizing, connecting your model provider, the sandboxed runtime and Docker configuration, TLS termination and scaling.
OpenHands itself is open-source software distributed under the MIT license. SecureAnyCloud charges for support services, not for the software.
Deploy on AWS
Launch OpenHands on AWS with 24/7 support from SecureAnyCloud.
View on Marketplace
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com