A laptop that sleeps can interrupt a long OpenHands task. The fastest fix is to deploy OpenHands Agent Canvas on an independent, rebuildable remote VM, validate it through a private path, and only add a remote Mac when the repository needs Xcode or another macOS-only toolchain.
This guide is for independent developers whose local tasks stop when the laptop closes, platform and DevOps engineers building a shared Agent Server, and engineering leads planning macOS, Xcode, or cross-platform build workloads.
Operational rule: keep the first deployment private. Add API key authentication, workspace limits, TLS, process recovery, and sandbox controls before public access.
Choose the execution boundary before installing anything
OpenHands Agent Canvas is a frontend for agent execution. The Agent Server performs the actual work. The automation backend handles scheduled or event-driven operations, while the workspace contains the repositories and files that the agent can read or modify. Agent Canvas can connect to more than one backend and switch between them from the interface. Read the OpenHands repository architecture and setup notes before selecting a topology.
That architecture gives you three practical deployment boundaries:
- Control service only: the VM runs the frontend, Agent Server, and automation service, while execution happens elsewhere.
- Control service plus build workspace: the VM also checks out repositories, runs tests, builds packages, and stores task artifacts.
- Control service plus external sandbox: the VM controls the workflow, but agent actions run inside a Docker-based environment or a separate execution host.
For most teams, the second boundary is the simplest starting point. It gives the agent a stable workspace without forcing you to operate several hosts on day one. The trade-off is important: direct host execution gives the agent access to the machine filesystem, environment, network, and available credentials. Treat this mode as a privileged machine.
Linux should be your default for code analysis, web services, dependency updates, and most backend builds. A remote Mac belongs in the design only when the task requires Xcode, Apple SDKs, simulators, signing tools, or another macOS-only dependency.
The deployment decision in one minute
| Deployment choice | Best fit | Main advantage | Main risk | SSHMac editorial score |
|---|---|---|---|---|
| Personal laptop | Short interactive tasks | No extra host to manage | Sleep, network changes, local secrets, accidental workspace access | 2/5 |
| Independent Linux VM | Long-running general development | Rebuildable, always available, easy firewall control | Host execution needs hardening | 5/5 |
| Docker sandbox on a Linux VM | Untrusted or tightly scoped tasks | Better separation from the host workspace | Volume mounts and Docker permissions still need review | 4/5 |
| Dedicated remote Mac | Xcode and Apple-platform builds | Native macOS toolchain | Higher operational cost and narrower use case | 4/5 |
| One shared host for every workload | Small trial only | Simple initial topology | Credentials, repositories, and build tasks become coupled | 2/5 |
The official self-hosting material accepts an always-on Linux or macOS host and presents a cloud VM or dedicated hardware as valid choices. It also identifies Ubuntu 24.04 LTS as a reasonable default and lists Node.js, uv, and basic tools such as curl and git for the Linux path. Use the current official instructions rather than copying an old image tag or assumed resource minimum. Review the OpenHands self-hosting guide when provisioning a new image.
First step: provision a private and rebuildable VM
Create the VM as infrastructure you can replace. Keep the repository data, service configuration, and secrets separate so a failed host does not become a permanent recovery project.
Before installing Agent Canvas, define:
- The administrative SSH source IP or VPN range.
- The directory that may contain agent-managed repositories.
- The credentials the agent is allowed to use.
- Whether builds run directly on the host or in a Docker sandbox.
- Whether the VM will be reachable only through SSH, a private network, or public HTTPS.
- The recovery path if the VM is deleted and recreated.
The first firewall posture should be deliberately narrow. Allow inbound SSH only from your own IP or VPN CIDR, and block the internal ingress, Agent Server, automation backend, and static server from outside the host.
Do not start by opening every port mentioned in a diagram. The single-host layout places nginx in front of a local ingress proxy. The internal services remain local, and the public entry point is the reverse proxy rather than the individual backend listeners. Verify the listener state on your selected release with:
sudo ss -lntp
The purpose of this check is not to guess a port. It is to prove which process is listening, which address it binds to, and whether the firewall matches that design.
Second step: run the smallest private stack
On an Ubuntu host, install the basic prerequisites:
sudo apt-get update
sudo apt-get install -y curl git
Install a supported Node.js runtime and uv using your preferred version manager or package source. The current OpenHands README lists Node.js 22.12.x or later and uv for the Agent Canvas launcher. Because runtime requirements can change, confirm them against the current Agent Canvas setup instructions before provisioning a new image.
For the first private launch, use the documented launcher:
npx @openhands/agent-canvas
The self-hosting workflow uses the --public flag for a public deployment. Do not begin with that mode while you are still checking the local path. First create an SSH tunnel from your workstation to the VM’s local ingress listener:
ssh -N -L 8000:127.0.0.1:8000 user@your-vm
Then open the local browser address used by the launcher. If your release exposes a different local path, follow the release README rather than assuming that a previous command remains valid.
Your first acceptance test should produce evidence, not just a visible page:
- The browser interface loads through the SSH tunnel.
- The selected backend reports as connected.
- A test repository is readable from the remote workspace.
- A small task produces continuing events instead of a single delayed response.
- The task record and generated files remain on the VM after the browser is closed.
- No internal service is reachable from an unrelated public network.
Agent Canvas is the interface layer, while the Agent Server is the REST API responsible for running agents. That distinction matters during troubleshooting: a loaded page does not prove that the execution backend, workspace, or event stream is healthy.
Third step: secure the first successful task
Generate a separate backend key and store it in your secret manager or protected service configuration:
export LOCAL_BACKEND_API_KEY="$(openssl rand -base64 32)"
The VM deployment workflow uses LOCAL_BACKEND_API_KEY and public mode so the key is not embedded in the frontend. Requests to the API must carry the matching session key, and users must enter the key before interacting with the public interface.
Treat the key as a credential with control over the agent machine. Do not put it in:
- A public Git repository.
- A frontend
.envfile that gets bundled into static assets. - Shell history shared with other administrators.
- A task prompt, issue description, or README.
- Application logs or browser screenshots.
Workspace scope is equally important. Create a dedicated directory such as /srv/openhands/projects and place only the repositories required for the workload inside it. Avoid mounting a home directory, cloud credential directory, SSH key directory, or production configuration directory into the agent workspace.
Direct execution and Docker sandboxing are not interchangeable. Direct execution is simpler, but the agent operates against the host filesystem and network. The Docker workflow maps a selected PROJECTS_PATH into the container, which narrows the visible project set, but volume mounts and Docker access still require review. The official project provides a Docker example using the ghcr.io/openhands/agent-canvas image and a host project directory in its container deployment documentation.
Run these boundary tests before public exposure:
- Ask the agent to read a permitted repository file.
- Ask it to read a file outside the workspace and confirm denial or absence.
- Send an unauthenticated API request and confirm rejection.
- Inspect logs for API keys, provider tokens, and full secret values.
- Ask it to execute a destructive command in a disposable test directory.
- Confirm that the firewall blocks direct access to internal listeners.
- Remove a temporary credential and repeat the task to verify failure is visible.
A successful coding task is not enough. You need evidence that the agent can do the intended work and cannot casually reach everything else.
Fourth step: make the service survive real operations
An SSH session is an administration channel, not a service supervisor. Use tmux for a quick deployment and systemd or an equivalent service manager for long-term operation. The self-hosting guide documents this service-management approach.
Use tmux only while proving the stack:
tmux new-session -d -s canvas 'npx @openhands/agent-canvas --public'
For a persistent Linux VM, create a system service with a protected environment file rather than placing the key directly in a broadly readable unit file:
[Unit]
Description=OpenHands Agent Canvas
After=network.target
[Service]
EnvironmentFile=/etc/openhands/agent-canvas.env
ExecStart=/usr/bin/npx @openhands/agent-canvas --public
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
The exact ExecStart path depends on how Node.js is installed. Check it with command -v npx before enabling the unit.
sudo systemctl daemon-reload
sudo systemctl enable --now agent-canvas
sudo systemctl status agent-canvas
Your recovery test should include four separate failures:
- Close the SSH session.
- Stop the process.
- Reboot the VM.
- Break and restore the network connection.
After each test, verify that the service returns, the backend becomes connected, the event stream resumes, and the task record remains readable. Add log rotation and a disk usage alert before multiple repositories or long-running tasks create a silent storage failure.
Fifth step: add TLS only after the private path works
Public browser access adds a reverse proxy, DNS, certificate management, and a larger authentication surface. It should be the second deployment phase, not the first.
The documented VM layout places nginx on HTTPS in front of an ingress proxy bound to localhost. The ingress routes the frontend, Agent Server API paths, socket connections, and automation paths to the corresponding local services. nginx therefore needs to proxy the single ingress entry point rather than expose each internal service separately.
The public sequence should be:
- Point a dedicated hostname to the VM.
- Keep the cloud firewall closed except for SSH while DNS propagates.
- Install nginx or your approved reverse proxy.
- Obtain a certificate through your selected certificate authority.
- Proxy HTTPS traffic to the local ingress address.
- Preserve long-lived connections used for live task events.
- Open only the public HTTP and HTTPS paths required by the proxy.
- Keep the Agent Server and automation listeners inaccessible from the internet.
- Confirm certificate renewal before declaring the deployment complete.
Do not treat HTTPS as a replacement for authorization. TLS protects the connection in transit. The API key determines whether a client can use the backend. The workspace boundary determines what the agent can reach after authorization.
Sixth step: register the remote backend in local Agent Canvas
A remote Agent Server can complement your local interface. The official instructions describe adding a backend through Manage backends, entering a memorable host name, the remote URL, and the session API key. An SSH tunnel can use a local address while public mode can use the HTTPS hostname.
Use distinct names such as:
local-sandboxlinux-build-vmmacos-signing-node
Then validate the switch instead of assuming it worked:
- Check the active backend name before starting a task.
- Confirm the repository path exists on that backend.
- Check the selected model and agent settings.
- Create a harmless marker file and verify its location.
- Review the task history from the expected backend.
- Stop the remote service and confirm that the UI shows the correct failure.
Backend switching is not file synchronization. If your laptop has uncommitted changes, the remote VM will not automatically receive them. Use Git, a controlled archive transfer, or an approved remote filesystem workflow. A safe pattern is to commit or stash the intended state, push it to a private repository, and let the remote backend clone or pull that exact revision.
When a remote Mac is justified
A remote Mac is an execution node for macOS-specific work, not a default replacement for a Linux VM. Route tasks there when the repository requires:
- Xcode or Apple SDKs.
- iOS or macOS simulator execution.
- Code signing and provisioning profiles.
- macOS-only package managers or system frameworks.
- Native Apple build artifacts that cannot be produced on Linux.
Keep ordinary code review, backend tests, web server checks, documentation tasks, and most dependency work on Linux. This separation reduces the number of secrets and toolchains attached to each host.
Before long-term use, run one complete repository loop on the Mac backend:
- Select the Mac backend.
- Fetch the exact repository revision.
- Install dependencies.
- Run the required build or test command.
- Produce the expected artifact.
- Restart the host or service.
- Confirm the workspace and task record recover.
- Repeat with the concurrency level you actually plan to support.
Do not assume that a Mac node solves synchronization, signing security, or capacity planning. It only supplies the operating system and toolchain boundary.
FAQ: remote VM access, ports, and recovery
The questions below cover the operational decisions that usually appear after the first successful launch.
Can Agent Canvas run on a cloud server?
Yes. The official self-hosting material supports a virtual machine or dedicated host, and the OpenHands README describes local, Docker, VM, and dedicated Mac execution options. A cloud VM is a strong default for long tasks because it is independent of your laptop. Keep its firewall private during setup and expose only the protected reverse proxy after authentication and recovery tests pass.
How do I keep Agent Canvas tasks running after SSH closes?
Use tmux for a quick test and systemd or an equivalent supervisor for a durable service. Configure restart behavior, then test logout, process failure, reboot, and network recovery. Also confirm that the repository and task state are stored remotely. A supervisor can restart a process, but it cannot recover uncommitted files that never left your local computer.
Which ports should a remote Agent Server expose?
Expose the reverse proxy, not every backend listener. The documented public topology uses HTTPS at nginx and keeps the ingress proxy, static server, Agent Server, and automation backend on local bindings. SSH should be restricted to your administrative source. Check the selected release and ss -lntp output before writing firewall rules because defaults may change.
When should OpenHands use a remote Mac?
Use one for Xcode, Apple SDKs, simulators, signing, and other macOS-only build requirements. Linux is the better general-purpose node for backend and web workloads. Add the Mac as a separate backend, use a separate workspace, and test a complete build after a restart. Do not route every task to a Mac simply because it is available.
What is the safe pattern for public Agent Canvas access?
Use a network firewall, public mode, a separately generated LOCAL_BACKEND_API_KEY, HTTPS, and a reverse proxy. Keep internal service ports private. Test unauthenticated requests, secret leakage, workspace escape, long-lived event connections, certificate renewal, and restart recovery. The agent can read and write files, execute shell commands, and reach the network on its host, so public access should follow boundary testing rather than precede it.
Final acceptance checklist
Use this checklist only after the service is functional. Every checked item should have a command result, browser observation, log entry, or task artifact behind it.
- [ ] The VM can be rebuilt without relying on undocumented manual changes.
- [ ] SSH access is limited to an administrator IP range or private network.
- [ ] The Agent Canvas UI works through an SSH tunnel before public exposure.
- [ ] The Agent Server reports as connected from the intended frontend.
- [ ] A test repository is readable from the intended remote workspace.
- [ ] A task returns continuing events and leaves a verifiable artifact.
- [ ]
LOCAL_BACKEND_API_KEYis stored outside public source and static frontend files. - [ ] Unauthenticated API requests fail.
- [ ] The agent cannot read unrelated credential and system directories.
- [ ] Direct host execution versus Docker sandbox scope has been documented.
- [ ] The service restarts after process failure and host reboot.
- [ ] Logs rotate and disk usage is monitored.
- [ ] TLS terminates at the reverse proxy with a tested renewal path.
- [ ] Internal ingress and backend ports are not publicly reachable.
- [ ] Backend switching shows the correct workspace and task history.
- [ ] Local uncommitted changes have an explicit Git or transfer workflow.
- [ ] A Mac backend is used only for macOS-specific toolchain tasks.
- [ ] The real repository completes a build and recovery loop before production use.
Configuration and risk comparison before public rollout
| Area | Direct host execution | Docker sandbox | Separate remote Mac |
|---|---|---|---|
| Workspace isolation | Lowest; agent can access host paths available to its process | Better when PROJECTS_PATH is narrowly mounted |
Depends on host permissions and workspace design |
| Toolchain coverage | Broad for the selected operating system | Broad inside the image, but host integration needs review | Best for Xcode and Apple-native builds |
| Recovery | Managed by the host service supervisor | Requires container restart and volume checks | Requires Mac service and host recovery checks |
| Credential exposure | High if environment and home directories are broad | Reduced only when mounts and Docker permissions are controlled | High-value signing credentials need separate handling |
| Best use | Trusted, controlled server workloads | Untrusted or scoped project execution | macOS-only build and signing stages |
| Rollout stage | Access path | Required evidence | Continue when |
|---|---|---|---|
| Private trial | SSH tunnel | UI, backend, repository, event stream | All four work without public exposure |
| Protected service | Local service manager | Logout, process stop, reboot recovery | Service returns and task state remains available |
| Public browser access | HTTPS reverse proxy | DNS, TLS, long-lived events, rejected unauthenticated calls | Internal listeners stay private |
| Team backend | Remote backend registration | Correct workspace, settings, and task history | Switching does not confuse repository state |
| Multi-platform build | Linux plus remote Mac | Complete repository build on each node | Tasks route by toolchain rather than convenience |
The current Agent Canvas release history shows continued changes across the frontend, backend integrations, and packaging, so pinning your deployment process to a release you have tested is safer than treating the latest launcher behavior as permanent. Recheck the Agent Canvas releases before a production rollout. The release page lists version 1.6.1 dated July 24, 2026 at the time of this review.
Last updated August 14, 2026. The deployment guidance was checked against the OpenHands README, self-hosting guidance, architecture documentation, Agent Canvas repository, and release history.
The practical choice after the VM trial
If your current setup is a laptop, the real weaknesses are clear: sleep interrupts work, local network changes break access, and the agent shares a machine with personal files and credentials. A Linux VM removes the first two problems and gives you a cleaner firewall and recovery boundary. It does not remove the need for workspace isolation or secret management.
If the repository depends on Xcode, simulators, signing, or another macOS-only toolchain, a Linux VM is not enough. In that case, keep the Linux node for general tasks and add a separately controlled remote Mac for the native build stage. SSHMac can be a sensible next step when you need a persistent Mac environment without turning your everyday laptop into the always-on build host; review the available remote Mac environment options and use the help center to verify the connection and access model before committing a production workflow.
The best long-term design is usually not “Mac for everything” or “Linux for everything.” It is a small Linux VM for durable Agent Canvas control and general development, plus a remote Mac only where the repository’s toolchain makes it unavoidable.