-
Notifications
You must be signed in to change notification settings - Fork 36
docs: PLTF-388 add Helm-based installer instructions for OpenHands Enterprise #628
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
aivong-openhands
merged 36 commits into
main
from
aivong/pltf-388-update-docsopenhandsdev-with-helm-based-installer
Jul 21, 2026
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
1deba7d
docs: PLTF-388 add Helm-based installer instructions for OpenHands En…
aivong-openhands fc3bfa1
docs: PLTF-388 make the starter values a usable install (auth, runtim…
aivong-openhands c8f6cce
docs: PLTF-388 link the create_github_app script for auth setup
aivong-openhands 1fb7701
docs: PLTF-388 single GitHub auth path, drop GitLab tab
aivong-openhands 412e526
docs: PLTF-388 note other auth providers are supported
aivong-openhands dd0f509
docs: PLTF-388 name Bitbucket Data Center explicitly
aivong-openhands 19610d8
docs: PLTF-388 simplify GitHub App script links
aivong-openhands a36a177
docs: PLTF-388 generalize auth prerequisite, GitHub as the example
aivong-openhands 07d8343
docs: PLTF-388 next-steps links and Replicated chart URL in upgrade e…
aivong-openhands c152da8
docs: PLTF-388 corrections from live end-to-end validation
aivong-openhands e824822
docs(k8s-install): clarify channel slug, BYO-cert, CLI install, and b…
aivong-openhands df1a37b
docs(k8s-install): drop channel-slug guidance (customers install from…
aivong-openhands 53117f1
docs(k8s-install): soften TLS trust language, trim storage-class trou…
aivong-openhands 8dceef5
docs(k8s-install): drop the support-bundle upload no-link note
aivong-openhands 5865a23
docs(k8s-install): cross-link Quick Start DNS reference
aivong-openhands 33a0b50
docs(k8s-install): drop redundant 'not optional' from TLS prerequisite
aivong-openhands 4325c3d
docs(k8s-install): remove DNS-01 issuer note from TLS prerequisite
aivong-openhands 16f6332
docs(k8s-install): simplify GitHub App prerequisite to a link
aivong-openhands 5071280
docs(k8s-install): make bring-your-own-cert the minimal TLS example
aivong-openhands d85723f
docs(k8s-install): regenerate llms-full.txt for BYO-cert example
aivong-openhands 4982f4e
docs(k8s-install): add generic default-cert pointer for non-Traefik c…
aivong-openhands d9c5a5d
docs(k8s-install): regenerate llms-full.txt
aivong-openhands 3975591
docs(k8s-install): trim 'no separate license file' aside from intro
aivong-openhands 036b244
docs(k8s-install): use dns-checks anchor; trim TLS explanation
aivong-openhands 49ee804
docs(k8s-install): trim helm-version prerequisite (covered in common …
aivong-openhands d807220
docs(k8s-install): trim cert-manager prereq and non-optional warning
aivong-openhands c9648be
docs(k8s-install): remove bring-your-own certificate note
aivong-openhands 555419f
Merge branch 'main' into aivong/pltf-388-update-docsopenhandsdev-with…
aivong-openhands b0e3662
docs(k8s-install): fix minimal values so the install actually works
aivong-openhands 2ca0c0e
docs(k8s-install): enable the bundled Keycloak in the minimal values
aivong-openhands 3249a4b
docs(k8s-install): require STORAGE_CLASS for sandbox volumes
aivong-openhands 9e11e69
docs: PLTF-388 link Replicated trial page in Helm install note
openhands-agent 02e88cb
docs: PLTF-388 use Helm v4 as prerequisite
openhands-agent d3b80c8
docs: PLTF-388 note embedded PostgreSQL is PoC-only with no migration…
openhands-agent 7836ddc
Merge branch 'main' into aivong/pltf-388-update-docsopenhandsdev-with…
aivong-openhands 0c1b381
docs: PLTF-388 recommend dedicated namespace for agent sandboxes
jlav File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,317 @@ | ||
| --- | ||
| title: Install with Helm | ||
| description: End-to-end installation of OpenHands Enterprise on Kubernetes using Helm | ||
| icon: ship | ||
| --- | ||
|
|
||
| OpenHands Enterprise is distributed as a Helm chart through the Replicated registry. | ||
| Your license credentials authenticate the chart download, and the chart embeds your | ||
| license automatically at install time. | ||
|
|
||
| <Note> | ||
| Helm-based installation requires an OpenHands Enterprise license. If you don't have | ||
| one yet, [register for a free 30-day trial](https://install.r9.all-hands.dev/openhands/signup) | ||
| or [contact our team](https://openhands.dev/contact) to get set up. | ||
| </Note> | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - A Kubernetes cluster with a default storage class and an ingress controller | ||
| (see [Resource Limits](/enterprise/k8s-install/resource-limits) for sizing guidance) | ||
| - **Helm v4 or later** | ||
| - `kubectl` access to the target cluster | ||
| - Your **license ID** and the **email address** registered with your license | ||
| (both provided by our team) | ||
| - **LLM credentials** from your chosen provider, for example an Anthropic API key | ||
| from the [Anthropic Console](https://console.anthropic.com/) | ||
| - DNS records you control, following the `app.<base-domain>` layout used | ||
| throughout this guide (with `openhands.example.com` as the base): | ||
| `app.openhands.example.com` (application), `auth.app.openhands.example.com` | ||
| (login), `runtime-api.openhands.example.com`, and a **wildcard** | ||
| `*.runtime.openhands.example.com` for runtime sandboxes. These point at your | ||
| cluster's ingress; see the Quick Start's | ||
| [DNS checks](/enterprise/quick-start#dns-checks) for the full hostname list. | ||
| - **TLS certificates covering all of the hostnames above**, which you provide. | ||
|
aivong-openhands marked this conversation as resolved.
|
||
| - An **authentication method** for user login — GitLab, Bitbucket Data Center, | ||
| and more are supported; this guide uses a **GitHub App**. See | ||
| [Creating a GitHub App](/enterprise/quick-start#create-a-github-app). | ||
|
|
||
| ## Step 1: Log in to the registry | ||
|
|
||
| Authenticate Helm against the Replicated registry using your license: | ||
|
|
||
| ```bash | ||
| helm registry login registry.replicated.com \ | ||
| --username <your-license-email> \ | ||
| --password <your-license-id> | ||
| ``` | ||
|
|
||
| ## Step 2: Create the namespaces and secrets | ||
|
|
||
| We recommend running agent sandboxes in a namespace separate from the | ||
| application. Sandboxes run agent-authored code, so a dedicated namespace keeps | ||
| them isolated from the application, database, and secrets. Create both | ||
| namespaces now: | ||
|
|
||
| ```bash | ||
| kubectl create namespace openhands | ||
|
aivong-openhands marked this conversation as resolved.
|
||
| kubectl create namespace openhands-runtimes | ||
| ``` | ||
|
|
||
| The chart references several Kubernetes secrets that you create ahead of | ||
| installation, all in the `openhands` namespace: | ||
|
|
||
| ```bash | ||
| kubectl -n openhands create secret generic jwt-secret \ | ||
| --from-literal=jwt-secret=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic keycloak-admin \ | ||
| --from-literal=admin-password=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic keycloak-realm \ | ||
| --from-literal=realm-name=allhands \ | ||
| --from-literal=server-url=http://keycloak \ | ||
| --from-literal=client-id=allhands \ | ||
| --from-literal=client-secret=<random-string> \ | ||
| --from-literal=smtp-password=<smtp-password> | ||
|
|
||
| kubectl -n openhands create secret generic postgres-password \ | ||
| --from-literal=username=postgres \ | ||
| --from-literal=password=<random-string> \ | ||
| --from-literal=postgres-password=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic redis \ | ||
| --from-literal=redis-password=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic lite-llm-api-key \ | ||
| --from-literal=lite-llm-api-key=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic admin-password \ | ||
| --from-literal=admin-password=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic default-api-key \ | ||
| --from-literal=default-api-key=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic sandbox-api-key \ | ||
| --from-literal=sandbox-api-key=<random-string> | ||
|
|
||
| kubectl -n openhands create secret generic litellm-env-secrets \ | ||
| --from-literal=ANTHROPIC_API_KEY=<your-llm-api-key> | ||
| ``` | ||
|
|
||
| Then create the secret for user authentication. Other providers (GitLab, | ||
| Bitbucket Data Center, and more) are supported, but this guide uses GitHub | ||
| throughout. If you don't have a GitHub App yet, run our | ||
| [script](/enterprise/quick-start#create-a-github-app) — its output provides | ||
| every value below, and the private key file is written to its `keys` | ||
| directory: | ||
|
|
||
| ```bash | ||
| kubectl -n openhands create secret generic github-app \ | ||
| --from-literal=app-id=<github-app-id> \ | ||
| --from-literal=app-slug=<github-app-slug> \ | ||
| --from-literal=client-id=<github-app-client-id> \ | ||
| --from-literal=client-secret=<github-app-client-secret> \ | ||
| --from-literal=private-key="$(cat <github-app-private-key>.pem)" \ | ||
| --from-literal=webhook-secret=<github-app-webhook-secret> | ||
| ``` | ||
|
|
||
| <Tip> | ||
| Generate strong random values (for example with `openssl rand -hex 32`) for each | ||
| `<random-string>` placeholder, and store them in your secret manager. To use an | ||
| existing PostgreSQL instance instead of the bundled one, see | ||
| [External PostgreSQL](/enterprise/external-postgres). | ||
| </Tip> | ||
|
|
||
| ## Step 3: Configure values | ||
|
|
||
| Create a `values.yaml` with your environment-specific configuration. The | ||
| minimum for a working installation covers five areas: application ingress and | ||
| TLS, user authentication, the runtime (sandbox) endpoints, conversation | ||
| storage, and your LLM provider. PostgreSQL and Redis run embedded in the | ||
| cluster; the bundled PostgreSQL needs a database name and database creation | ||
| turned on, both shown below (to use your own database instead, see | ||
| [External PostgreSQL](/enterprise/external-postgres)). | ||
|
|
||
| <Warning> | ||
| The embedded PostgreSQL is intended for proof-of-concept and evaluation use | ||
| only, not production. For production deployments we recommend bringing your | ||
| own managed PostgreSQL — see | ||
| [External PostgreSQL](/enterprise/external-postgres). There is no officially | ||
| supported migration path from the embedded PostgreSQL instance to an external | ||
| one, so plan to switch to an external database before you load production | ||
| data. | ||
| </Warning> | ||
|
|
||
| The example below uses Traefik, the chart's default ingress class; set | ||
| `ingress.class` and the annotations to match your controller. | ||
|
|
||
| ```yaml | ||
| ingress: | ||
| enabled: true | ||
| host: app.openhands.example.com | ||
| class: traefik | ||
|
|
||
| # This guide brings its own certificate, terminated at the ingress controller, | ||
| # so the chart's per-ingress TLS is disabled (see the note below the example). | ||
| tls: | ||
| enabled: false | ||
|
|
||
| # Enables login via the GitHub App created in Step 2 | ||
| github: | ||
| enabled: true | ||
|
|
||
| # Bundled PostgreSQL: name the application database and let the chart create | ||
| # the databases it needs on first start | ||
| postgresql: | ||
| auth: | ||
| database: openhands | ||
| databaseMigrations: | ||
| createDatabases: true | ||
|
|
||
| # Login is served by the bundled Keycloak at auth.<ingress.host> — both the | ||
| # component and its ingress must be enabled for users to be able to log in | ||
| keycloak: | ||
| enabled: true | ||
| ingress: | ||
| enabled: true | ||
| hostname: auth.app.openhands.example.com | ||
| tls: false | ||
|
|
||
| # Where agent sandboxes run. The runtime API needs its own hostname, and each | ||
| # sandbox gets a subdomain under your wildcard DNS record. | ||
| sandbox: | ||
| apiHostname: https://runtime-api.openhands.example.com | ||
|
|
||
| env: | ||
| RUNTIME_URL_PATTERN: "https://{runtime_id}.runtime.openhands.example.com" | ||
| LITELLM_DEFAULT_MODEL: litellm_proxy/claude-sonnet-4-5 | ||
|
|
||
| runtime-api: | ||
| # Create sandboxes in the dedicated namespace from Step 2, isolated from the | ||
| # application workloads. | ||
| sandbox_namespace: openhands-runtimes | ||
| ingress: | ||
| enabled: true | ||
| host: runtime-api.openhands.example.com | ||
| tls: false | ||
| databaseMigrations: | ||
| createDatabases: true | ||
| env: | ||
| # Base domain for the per-sandbox ingresses ({runtime_id}.<RUNTIME_BASE_URL>); | ||
| # must match RUNTIME_URL_PATTERN above. RUNTIME_DISABLE_SSL defaults to | ||
| # "true" — it must be "false" so sandbox URLs are served over https. | ||
| RUNTIME_BASE_URL: runtime.openhands.example.com | ||
| RUNTIME_DISABLE_SSL: "false" | ||
| # Storage class for sandbox volumes. The chart default (standard-rwo) only | ||
| # exists on GKE — set a storage class from `kubectl get storageclass` or | ||
| # sandboxes will never start. | ||
| STORAGE_CLASS: <your-storage-class> | ||
|
|
||
| # Store conversation data in the bundled MinIO, persisted to a volume | ||
| filestore: | ||
| ephemeral: true | ||
| minio: | ||
| persistence: | ||
| enabled: true | ||
|
|
||
| litellm-helm: | ||
| enabled: true | ||
| proxy_config: | ||
| model_list: | ||
| - model_name: claude-sonnet-4-5 | ||
| litellm_params: | ||
| model: anthropic/claude-sonnet-4-5 | ||
| api_key: os.environ/ANTHROPIC_API_KEY | ||
| ``` | ||
|
|
||
| ## Step 4: Install | ||
|
|
||
| ```bash | ||
| helm install openhands oci://registry.replicated.com/openhands/openhands \ | ||
| --namespace openhands \ | ||
| --values values.yaml | ||
| ``` | ||
|
|
||
| Watch the workloads come up: | ||
|
|
||
| ```bash | ||
| kubectl get pods -n openhands --watch | ||
| ``` | ||
|
|
||
| The first install pulls all container images, which can take a while. Along with the | ||
| application components you'll see a `replicated` pod — the Replicated SDK, which | ||
| handles license verification and powers the support tooling below. | ||
|
|
||
| ## Step 5: Validate the installation | ||
|
|
||
| The chart ships preflight checks that validate your cluster against the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎊 |
||
| application's requirements. Run them with the | ||
| [`preflight` CLI](https://troubleshoot.sh/docs/preflight/introduction/): | ||
|
|
||
| ```bash | ||
| preflight secret/openhands/openhands-preflight | ||
| ``` | ||
|
|
||
| <Tip> | ||
| The `preflight` and `support-bundle` CLIs are both part of | ||
| [Troubleshoot](https://troubleshoot.sh/docs/#installation). Install them with: | ||
|
|
||
| ```bash | ||
| curl -L https://krew.sh/preflight | bash | ||
| curl -L https://krew.sh/support-bundle | bash | ||
| ``` | ||
| </Tip> | ||
|
|
||
| Then confirm the application is reachable at your configured hostname and log in. | ||
|
|
||
| ## Next Steps | ||
|
|
||
| The install above is a minimal working baseline. Features and tuning are values | ||
| overrides on the same release — edit your `values.yaml` and apply with | ||
| `helm upgrade` using the chart URL from Step 4: | ||
|
|
||
| <CardGroup cols={2}> | ||
| <Card title="Resource Limits" icon="gauge-high" href="/enterprise/k8s-install/resource-limits"> | ||
| Size memory, CPU, and replicas for production workloads. | ||
| </Card> | ||
| <Card title="External PostgreSQL" icon="database" href="/enterprise/external-postgres"> | ||
| Use your own PostgreSQL instead of the embedded instance. | ||
|
aivong-openhands marked this conversation as resolved.
|
||
| </Card> | ||
| <Card title="Analytics" icon="chart-line" href="/enterprise/analytics"> | ||
| Enable conversation analytics with Laminar. | ||
| </Card> | ||
| <Card title="Plugin Marketplace" icon="puzzle-piece" href="/enterprise/plugin-marketplace"> | ||
| Offer curated plugins to your users. | ||
| </Card> | ||
| </CardGroup> | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Generate a support bundle | ||
|
|
||
| If something isn't working, generate a support bundle with the | ||
| [`support-bundle` CLI](https://troubleshoot.sh/docs/support-bundle/introduction/). | ||
| It discovers the diagnostic specs that ship with the chart and collects logs, | ||
| resource states, and health checks from the installation: | ||
|
|
||
| ```bash | ||
| support-bundle --load-cluster-specs --namespace openhands | ||
| ``` | ||
|
|
||
| ### Send it to us | ||
|
|
||
| Upload the resulting archive directly to our support team — the upload | ||
| authenticates with the license embedded in the bundle: | ||
|
|
||
| ```bash | ||
| support-bundle upload support-bundle-<timestamp>.tar.gz | ||
| ``` | ||
|
|
||
| ### Common issues | ||
|
|
||
| | Symptom | Likely cause | | ||
| |---------|--------------| | ||
| | `helm install` fails with a template error mentioning `replicated` | Helm version too old — upgrade to v4+ | | ||
| | `helm registry login` or chart pull returns 401/403 | License credentials incorrect, or the license isn't enabled for Helm installs — contact support | | ||
| | Preflight warns about node memory | Cluster nodes below the recommended sizing — see [Resource Limits](/enterprise/k8s-install/resource-limits) | | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.