Getting started
Prerequisites
Section titled “Prerequisites”- A Nebari cluster running the Nebari Infrastructure Core stack:
nebari-operator
v0.1.0-alpha.20or later (provides theNebariAppCRD; the version this pack’s contract test and dev loop pin), Envoy Gateway with the sharedpublic(orinternal) Gateway, and a Keycloak realm (nebariby default). - cert-manager with a cluster issuer — only when TLS is enabled (the default).
- Helm 3.8+ and
kubectlwith cluster-admin for the install (the chart creates a CRD and ClusterRoles). - Namespace opt-in: the nebari-operator only reconciles namespaces labeled
nebari.dev/managed=true— label the release namespace and every namespace apps may be launched into. - Sizing: the pack requests 300m CPU / 448Mi memory (limits 1.5 CPU / 896Mi) for its four
pods, plus one pod per launched app sized by the App’s
runtime.resources(no default). - Optional: metrics-server for per-app CPU/memory in the UI.
Read the Known limitations before a demo: group restrictions are not enforced by the gateway yet, and users manage only their own apps (admins manage all of them).
Install
Section titled “Install”Create the namespaces apps will run in first. The chart gives the API a RoleBinding in
each namespace in api.allowedNamespaces (default apps), so they must exist, and the
nebari-operator only processes namespaces that opt in:
kubectl create namespace appskubectl label namespace apps nebari.dev/managed=trueThen install:
helm install nebari-apps charts/nebari-apps \ --namespace nebari-apps --create-namespace \ --set clusterDomain=example.ai \ --set keycloak.url=https://keycloak.example.ai/auth
# The nebari-operator only processes namespaces that opt in:kubectl label namespace nebari-apps nebari.dev/managed=trueOr from the published chart with the ready-made values file
(examples/nebari-values.yaml;
edit the two hostnames):
helm install nebari-apps oci://ghcr.io/nebari-dev/apps-pack/charts/nebari-apps \ --namespace nebari-apps --create-namespace -f examples/nebari-values.yamlThis deploys four components:
| Component | Where it ends up |
|---|---|
| apps-operator | Watches App resources cluster-wide. |
| apps-api | In-cluster Service; the UI proxies /api to it same-origin. |
| apps-ui | https://apps.example.ai — with a landing-page tile (“Apps”). |
| apps-mcp | https://apps.example.ai/mcp — agent tools, proxied by the UI (see MCP server). |
Every app launched afterwards gets https://<subdomain>.apps.example.ai.
Key values
Section titled “Key values”The full reference, including every component’s values and the NebariApp fields the chart
emits, is on the Configuration page.
| Value | Default | Purpose |
|---|---|---|
clusterDomain | — (required) | The cluster’s base domain. |
appsDomain | apps.<clusterDomain> | Domain apps are served under. |
tls.enabled | true | Set false to serve plain HTTP (no certificates). |
keycloak.url | — | Browser-facing Keycloak base URL (required when auth is on). |
keycloak.realm | nebari | Keycloak realm. |
keycloak.internalUrl | — | Optional in-cluster Keycloak URL (split horizon) for JWKS. |
api.auth.enabled | true | Keycloak JWT auth for the API + keycloak-js login in the UI. |
api.allowedNamespaces | ["apps"] | Namespaces users may launch into via the API/UI/MCP. Empty list = every namespace labeled nebari.dev/managed=true. |
apps.landingPage.enabled | false | Cluster default for landing-page tiles of launched apps; apps override with spec.landingPage.enabled. |
ui.hostname | <appsDomain> | Where the UI itself is served. |
ui.title, ui.branding.* | — | Rebrand the UI (title, logos, favicon, theme, banners) — see Branding. |
ui.landingPage.* | ”Apps” tile | Landing-page tile label, description, category, icon, and health check — see Branding. |
gateway | public | Shared Gateway apps attach to (public | internal). |
staticImage | nginxinc/nginx-unprivileged:1.27-alpine | Serves static app content. |
gitImage | alpine/git:v2.47.2 | Init-container image for git sources. |
pythonImage | ghcr.io/prefix-dev/pixi:0.68.1-noble | Runs Python/pixi apps (runtime.pixiTask). |
Launch your first app
Section titled “Launch your first app”
appsis the default entry inapi.allowedNamespaces— to launch into other namespaces from the UI/API/MCP, add them to that list (or set it empty to allow every managed namespace). A namespace added to the list must exist beforehelm upgrade.kubectl applyis only gated by the namespace label.
Then either open the UI at https://apps.example.ai and use the launch form, or apply a
sample App:
kubectl apply -n apps -f examples/static-inline-app.yaml # or python-inline-app.yamlkubectl get apps -n apps -wNAME SOURCE PHASE URLdocs-site inline Running https://docs-site.apps.example.aiWhen PHASE reaches Running, open the URL. Private apps redirect to Keycloak; public apps
(access.public: true) are reachable anonymously.
Connect a coding agent
Section titled “Connect a coding agent”Point Claude Code (or any MCP client) at the cluster and launch with natural language:
claude mcp add --transport http nebari-apps https://apps.example.ai/mcpThe first tool call will ask you to log in via the Keycloak device flow (the agent shows a verification URL and code). See the MCP server guide for the tool list and the scaffolding skill for generating apps the agent can launch.
Verify a deployment
Section titled “Verify a deployment”# The App's own status: phase, URL, replicas, conditionskubectl describe app docs-site -n apps
# The children the operator createdkubectl get deploy,svc,cm,nebariapp -n apps
# Expected App conditions:# Validated: True - spec is coherent, namespace opted in# WorkloadReady: True - all replicas ready# RoutingReady: True - the NebariApp reports Ready (routing/TLS/auth)Deleting an App cascades: the Deployment, Service, ConfigMap, and NebariApp (and through
it the HTTPRoute, certificate, and OIDC client) are all garbage-collected.