Artificial Intelligence (AI) AWS

OpenHands AI Software Development Agent on AWS User Guide

| Product: OpenHands on AWS

Overview

This image runs OpenHands 1.8, the open source AI software engineering agent (OpenHands/OpenHands, MIT), on Ubuntu 24.04 LTS. You describe a task in a browser and 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.

OpenHands runs as the official application container under Docker, bound to the loopback address 127.0.0.1:3000; nginx fronts it on port 80 with HTTP Basic Authentication. An unauthenticated /healthz endpoint stays open for load balancer probes; everything else requires the password. The default security group opens port 22 (SSH), port 80 (HTTP) and port 443 (HTTPS) only, so port 3000 is never reachable from outside the instance.

On the first boot of every deployed instance a one-shot service generates a fresh password, unique to that instance, and writes it to /root/openhands-credentials.txt (mode 0600, 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, but 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 is a required first-run step, not an optional extra.

Your key is stored only on your own instance, under /var/lib/openhands, and every model request goes directly from your instance to the provider you chose.

OpenHands first run: the AI Provider Configuration step asks for your own model provider API key

Why the whole application sits behind a password

OpenHands has no built-in login of its own — upstream designs it to be 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 is what keeps the agent private to you, and 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 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

  • An AWS account subscribed to this product in AWS Marketplace.
  • An EC2 key pair in your target region for SSH access.
  • A security group allowing 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). You will paste it in on first visit.
  • Recommended instance type: m5.large. Use m5.xlarge or larger if you expect several concurrent agent conversations, since 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

  1. Open the product page in AWS Marketplace and choose Continue to Subscribe, then Continue to Configuration.
  2. Select the OpenHands on Ubuntu 24.04 delivery option and your region, then Continue to Launch.
  3. Choose an instance type (m5.large or larger), your VPC/subnet, key pair and the security group described above, and launch.

Step 2 - Launch from the AWS CLI

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

ssh -i your-key.pem ubuntu@<instance-public-ip>

Step 4 - Confirm the services are running

systemctl is-active docker.service nginx.service

Both report active:

active
active

Step 5 - Confirm the OpenHands container

docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'

One application container runs. This image ships OpenHands, Docker and nginx and nothing else — there is no separate database or cache tier to operate:

NAMES           IMAGE                                          STATUS
openhands-app   docker.openhands.dev/openhands/openhands:1.8   Up 15 minutes

Step 6 - Confirm the dedicated storage volumes

df -h / /var/lib/docker /var/lib/openhands

Agent state and the Docker image store are each on their own volume, separate from the operating system disk:

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/openhands

Step 7 - Confirm the security gate

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=401

Step 8 - Retrieve your instance password

sudo grep -E '^OPENHANDS_(URL|USERNAME)=' /root/openhands-credentials.txt

That prints the address and the user name. To read the password itself:

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, but 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 that, you signed in via the address bar: clear it back to http://<instance-public-ip>/ and use the sign-in prompt instead.

Step 10 - Connect your model provider

On the first visit OpenHands opens AI Provider Configuration. Choose your LLM Provider, pick a LLM Model, paste your own API Key, and choose Save. Until you do, the agent cannot run a task.

You can change this at any time under Settings. A newly launched instance has no model profile saved, which confirms no credential ships in the image:

The LLM settings page on a new instance reports no saved profiles

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.

You can 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:

Model Context Protocol server settings, with no servers configured on a new instance

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-app

View the application logs

sudo docker logs --tail 20 openhands-app

Back 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/cloudimg-openhands. Keep the auth_basic directives in place when you do — they are the control that keeps the agent private.

Security notes

  • The agent can run arbitrary commands and controls Docker on this instance. Treat access to the web interface as equivalent to shell access to the instance.
  • Restrict port 80 (and 443) in the security group to the addresses your team uses, rather than leaving it open to the internet.
  • Keep the per-instance password, or replace it with your own, but never remove the gate without an equivalent control.
  • Your model provider key is stored on the instance. Anyone with access to the interface can use it, and so can the agent.

Support

This image is published by cloudimg 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 licence; cloudimg charges for support services, not for the software.