npx @openhands/agent-canvas locally.
When to Use It
A Modal backend is a good fit when you want to:- Offload agent execution to the cloud without managing your own VM or Docker host
- Take advantage of Modal’s per-second billing and free-tier credits
- Get a persistent, always-warm backend with minimal setup — or scale to zero when idle to reduce costs
Prerequisites
- A Modal account (free tier includes $30/month credit)
- Python 3.12+
- Agent Canvas running locally — see Setup
- An LLM API key (OpenAI, Anthropic, etc.)
1. Install the Modal CLI
modal setup opens a browser to authenticate. Your credentials are saved to \~/.modal.toml.
2. Create a Modal Secret
Generate an API key and encryption key, then store them as a Modal secret:3. Deploy
Save the following asdeploy.py:
min_containers=1) so there’s no cold-start latency. To scale to zero when idle instead (lower cost, but ~10-30s cold start on first request):
4. Connect Agent Canvas
- Open Agent Canvas locally (
npx @openhands/agent-canvas). - Click the backend switcher → Manage Backends → Add Backend.
- Fill in:
- Name — e.g.
Modal - Host / Base URL — the URL from step 3 (e.g.
https://openhands-agent-server--agentserver-serve.modal.run) - API Key — the
API_KEYvalue from step 2
- Name — e.g.
- Save and select it as the active backend.
5. Configure Your LLM
The agent server doesn’t come with LLM credentials — you provide them once through the Canvas UI:- With the Modal backend selected, open Settings.
- Choose a provider (e.g. OpenAI, Anthropic).
- Enter your API key and select a model.
- Save.
OH_SECRET_KEY) and persist across redeploys.
Cost
Modal charges per-second for CPU and memory. TheMODAL_ALWAYS_ON setting controls whether the container stays warm between requests:
Hourly rate breakdown (2 vCPU / 4 GB):
Always-on costs ~$3.40/day (~$102/month). Modal’s $30/month free credit covers about 9 days.
Scale-to-zero costs only for the hours the container is running. At 8 hours/day on workdays, that’s roughly ~$1.12/day (~$25/month). The first request after an idle period takes ~10-30s while the container cold-starts; after that, the
scaledown_window (10 min) keeps it warm between interactions.
To stop the deployment entirely and avoid all charges: modal app stop openhands-agent-server. Your data on the Modal volume persists.
Limitations
- No Docker-in-Docker. Modal containers don’t support nested Docker. The agent executes code directly on the container filesystem (same model as running
npx @openhands/agent-canvaslocally). Tools that require Docker won’t work. - Single-user only. Pinned to one container (
max_containers=1) because the agent server uses SQLite and in-memory state that can’t be shared across containers. - Public URL. The
*.modal.runendpoint is internet-reachable. All API endpoints require the API key, but the URL itself is public.
Security
The agent server is protected by the API key you created in step 2. Every REST and WebSocket request is rejected without it. Modal provides TLS on all*.modal.run endpoints automatically.
The *.modal.run URL is not indexed or easily guessable, but treat it as sensitive — it appears in terminal output, browser history, and Canvas localStorage.
Rotating the API Key
If you suspect the API key has been leaked:Upgrading
To update to a newer agent-server version, changeAGENT_SERVER_IMAGE_TAG in deploy.py to the desired tag (e.g. 1.25.0-python) and redeploy:
ghcr.io/openhands/agent-server. Use the -python variant.
Troubleshooting
Check the server logs:Tearing Down
To stop the deployment and stop incurring costs:openhands-data) is preserved. Redeploy later with modal deploy deploy.py and everything picks up where you left off. To permanently delete the volume:

