OpenHands / OpenHands/enterprise
Kubernetes runtimes need separate public, control, and callback URLs
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4
- Forks
- 2
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 101
Description
Summary
Self-hosted Kubernetes deployments need separate URLs for:
- browser-facing access to a sandbox through ingress/Gateway API; and
- trusted server-side control traffic from OpenHands and runtime-api directly to the runtime's cluster-local Service.
The current remote-runtime contract exposes only runtime["url"]. OpenHands uses that same URL both as a browser-facing exposed URL and for server-side agent-server health/control calls. This forces trusted control traffic through public ingress, where the originating workload identity may be replaced by the ingress proxy identity and the full agent-server API must be reachable on the browser data plane.
The callback side has a related coupling: sandbox webhook, provider-secret lookup, and default MCP URLs are constructed from the public web_url. An isolated sandbox may need a distinct internal-only callback hostname while the browser continues using the public application hostname.
Affected versions
- OpenHands Enterprise
1.56.0 - Current
mainat338d41ee584ea4f7db27ac425cc0d75364d2c5ef
Current behavior
RemoteSandboxService._to_sandbox_info()turns the single runtime URL intoAGENT_SERVERand derives browser worker URLs from it.SandboxServiceperforms server-side/alivechecks using that exposedAGENT_SERVERURL.RemoteSandboxServicebuildsOH_WEBHOOKS_0_BASE_URLfrom the publicweb_url.- Provider-secret lookup uses
self.web_url. - The default MCP URL also uses
self.web_url.
Why this matters
A secure Kubernetes deployment may intentionally enforce all of the following:
- browser traffic reaches a runtime only through authenticated ingress;
- OpenHands core and runtime-api reach agent-server directly through a cluster-local Service;
- workload identity is preserved for server-side network policy;
- sandbox RFC1918 access is denied by default;
- sandbox callbacks can reach one narrow internal Gateway without gaining broad private-network access;
- callback, secret-lookup, and MCP requests retain their existing application-layer authentication.
The single URL/public-host coupling makes those requirements conflict.
Requested contract
One possible backward-compatible shape would be:
public_url: returned to browser-facing consumers and used to derive VS Code/worker URLs;control_url: used only by runtime-api and OpenHands for/aliveand the full server-side agent API;- a separately configurable sandbox callback base URL used for
OH_WEBHOOKS_0_BASE_URL, provider-secret lookup, and default MCP construction; - existing
url/web_urlbehavior retained as fallback when the new values are absent.
The runtime-api should perform readiness checks against the control URL when configured. OpenHands should retain the public URL in exposed browser metadata while all server-side agent calls prefer the control URL.
Acceptance criteria
- A Kubernetes runtime can advertise both a public ingress URL and a cluster-local control URL.
- runtime-api readiness and OpenHands server-side agent calls use the control URL.
- browser-facing sandbox/worker links continue to use the public URL.
- sandbox webhook, provider-secret lookup, and default MCP URLs can use a callback base distinct from the public application URL.
- existing deployments that provide only the current URL fields remain compatible.
- tests prove the public and control paths cannot be accidentally interchanged.
No private IPs, credentials, tokens, or deployment-specific hostnames are included in this report.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in openhands/app_server/sandbox/remote_sandbox_service.py at _to_sandbox_info() and the webhook URL construction, then trace the /alive checks in sandbox_service.py. Review the provider-secret and default MCP URL callers in live_status_app_conversation_service.py, along with the runtime-api readiness path. Done means public, control, and callback URLs remain distinct, legacy fields still fall back correctly, and tests prevent path interchange.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kubernetes, python
- Domain
- backend-api-design, cloud, infrastructure
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100