Skip to content

Self-hosted Okahu

Self-hosted Okahu runs the control plane, trace store, evaluation service, and portal UI as workloads in a Kubernetes cluster you operate. You bring Kubernetes, Postgres, and Azure OpenAI; Okahu provides the installer and the container images.

Contact Okahu for the installer bundle and image-pull credentials.

Deployment options

Option What it does Who it is for
1. Kubernetes only Runs the installer against a cluster, Postgres, and Azure OpenAI you already own. Any Kubernetes distribution that can provision a public LoadBalancer. Teams that already run Kubernetes in production.
2. Full cloud deploy Okahu scripts create the cloud resources (cluster, Postgres, Azure OpenAI, container registry) and run the installer. Azure AKS today; EKS and GKE on request. Teams that want a single-command install from scratch.
3. Agentic install A coding agent (Claude Code or OpenAI Codex) drives the Option 2 scripts and surfaces errors in context. Teams that already operate infrastructure through a coding agent.

What you need

  • Kubernetes. A cluster whose current kubectl context points at it, with permission to create namespaces and provision a public LoadBalancer. kubectl, helm ≥ 3.8, python3, curl, and tar on your workstation.
  • Postgres 16 reachable from inside the cluster. Okahu uses the database exclusively.
  • Azure OpenAI with a gpt-4.1 deployment on Standard, GlobalStandard, or DataZoneStandard. The deployment name must be the literal string gpt-4.1.
  • The installer bundle okahu-standalone-<version>.tar.gz and image-pull credentials from Okahu.

Options 2 and 3 relax some of these (Okahu's scripts provision the cluster, Postgres, and Azure OpenAI on Azure); see the sections below.

Option 1. Kubernetes only

Default mode is simple: a shared bearer token guards the backend APIs.

tar xzf okahu-standalone-<version>.tar.gz
cd okahu-standalone-<version>

OKAHU_REGISTRY_TOKEN="$(cat ./registry.token)" \
OKAHU_AZURE_OPENAI_KEY="$(cat ./aoai.key)" \
./install.sh \
  --pg-url                "postgresql://USER:PASS@YOUR_PG_HOST:5432/DB?sslmode=require" \
  --registry-user         "YOUR_REGISTRY_USERNAME" \
  --azure-openai-endpoint "https://YOUR_AOAI.openai.azure.com/" \
  --azure-openai-model    "gpt-4.1" \
  --release               "YOUR_RELEASE_TAG" \
  --portal-ux-version     "YOUR_PORTAL_UX_VERSION"

Takes about 10 minutes. The installer prints the LoadBalancer address, tenant id, shared auth token, and the first API key. Save the API key from this output; it is stored as a hash and will not be shown again.

Pass secrets through env vars (as above) rather than CLI flags, so tokens stay out of ps and shell history.

HTTPS and Entra ID sign-in

Add these flags to serve HTTPS behind a Let's Encrypt certificate and require Microsoft Entra ID sign-in:

./install.sh ... \
  --hostname              "okahu.your-domain.example" \
  --acme-email            "ops@your-company.example" \
  --auth-provider         entra \
  --azure-ad-tenant-id    "YOUR_ENTRA_TENANT_ID" \
  --azure-ad-client-id    "YOUR_ENTRA_APP_CLIENT_ID"

Point the DNS name at the LoadBalancer's public IP before running, or the ACME challenge fails. In Entra mode, each user signs in with their own account; there is no shared token.

Pulling images from your own registry

The installer pulls charts and images from any OCI-compliant registry: Azure Container Registry, Amazon ECR, Google Artifact Registry, Harbor, Quay, Nexus. Populate the registry once per release with mirror.sh (shipped in the bundle):

./mirror.sh \
  --dest-host         <registry>.example.com \
  --dest-user         <username> \
  --dest-token-file   ./registry.token \
  --release           "YOUR_RELEASE_TAG" \
  --portal-ux-version "YOUR_PORTAL_UX_VERSION"

Then install from your registry by adding --registry-host, --registry-path, and --registry-user to the install command above. On AKS attached to an ACR via az aks update --attach-acr, the cluster uses its managed identity to pull; the registry token is only needed by mirror.sh.

A fully air-gapped install also needs the upstream Traefik, cert-manager, and KubeRay charts and images mirrored. Contact Okahu for the air-gapped bundle.

Lifecycle

  • Verify. curl https://<hostname>/okahu/eval/health returns 200. The portal UI is at https://<hostname>/.
  • Upgrade. Re-run install.sh with a new --release <tag>. Helm upgrades every chart in place with --atomic.
  • Uninstall. helm uninstall -n okahu <release> for each chart, then kubectl delete ns okahu okahu-ray traefik cert-manager. The Postgres database, Azure OpenAI resource, and Entra app registration are not touched.

Current limits

  • LLM provider. Azure OpenAI with gpt-4.1 only. OpenAI direct, Bedrock, and Anthropic are not supported today.
  • Postgres. Version 16.
  • Portal UI image. Pin --portal-ux-version to a value Okahu validated; the moving latest tag is not recommended for production.

Option 2. Full cloud deploy

Okahu scripts create the resource group, AKS cluster, Postgres Flexible Server, Azure OpenAI resource, and container registry, then run the installer from one YAML config. Completes in about 25 minutes and writes .env.<prefix> with the LoadBalancer address, tenant id, API key, and every Azure resource name.

Azure AKS today. AWS EKS and Google GKE are planned; on those clouds, use Option 1.

Prerequisites (in addition to the common list)

  • Azure subscription on which you have Owner or Contributor.
  • az CLI ≥ 2.56, logged in and set to the target subscription with az account set --subscription <id>.
  • Permission to update Entra app registrations (Application.ReadWrite.All or Cloud Application Administrator). The installer adds the portal's redirect URI to the app.
  • pyyaml installed on your Python so the entry point can parse the config.
  • Region quota for a Standard_D4s_v5 node pool (≥ 12 vCPUs) and your chosen gpt-4.1 SKU.

Install

Okahu ships the Option 2 artifacts in okahu-standalone-installer-<version>.tar.gz (a superset of the Option 1 bundle).

okahu-standalone-installer-<version>/
├── config.example.yaml
├── bundle/                 # install.sh, mirror.sh, Helm values
└── scripts/
    ├── full-deploy.sh      # Entry point
    ├── preflight-setup.sh  # Run once per Azure sub + Entra tenant
    ├── deploy.sh           # Per-cluster provisioning + install
    ├── test.sh             # Smoke suite
    ├── status.sh           # Live snapshot
    ├── redeploy.sh         # Helm upgrade
    ├── rotate-secret.sh    # Shared-bearer rotation (simple mode)
    └── teardown.sh         # Delete the resource group

Run:

tar xzf okahu-standalone-installer-<version>.tar.gz
cd okahu-standalone-installer-<version>

cp config.example.yaml config/prod.yaml
# Edit config/prod.yaml. See the schema below.

./scripts/full-deploy.sh --config config/prod.yaml

Configuration schema

prefix: prod                         # Prefix for every Azure resource name
region: eastus                       # Azure region

aks:
  node_count: 3
  node_sku: Standard_D4s_v5

auth:
  provider: entra                    # entra | simple
  hostname: prod-okahu.eastus.cloudapp.azure.com
  dns_label: prod-okahu
  acme_email: ops@your-company.example
  redirect_uri: https://prod-okahu.eastus.cloudapp.azure.com/en
  entra:
    tenant_id: YOUR_ENTRA_TENANT_ID
    client_id: YOUR_ENTRA_APP_CLIENT_ID

release:
  tag: <supplied by Okahu>
  portal_ux_version: <supplied by Okahu>

registry:
  mode: jfrog                        # jfrog | acr-mirror
  # acr-mirror creates a per-cluster ACR, populates it with mirror.sh,
  # and installs from it. Zero live traffic to okahu.jfrog.io after the mirror step.
  acr_sku: Basic

To add a second cluster, copy the YAML and change prefix, hostname, dns_label, and redirect_uri.

Operations

Every script reads the same YAML.

./scripts/test.sh           --config config/prod.yaml
./scripts/status.sh         --config config/prod.yaml
./scripts/redeploy.sh       --config config/prod.yaml
./scripts/rotate-secret.sh  --config config/prod.yaml
./scripts/teardown.sh       --config config/prod.yaml --yes
Script What it does
test.sh 17-case smoke suite: health endpoints, auth negatives, tenant and API-key readback, ingest round-trip, Kubernetes readiness. Opens an HTML report.
status.sh Read-only snapshot of namespaces, deployments, Traefik LoadBalancer, RayCluster, Postgres state.
redeploy.sh Re-runs install.sh against the existing cluster; skips Azure provisioning. Use after bumping release.tag, after a chart value change, or to recover from a partial install.
rotate-secret.sh Simple mode only. New shared bearer token in okahu-secrets, rolling restart of every backend deployment. Tenant API keys (okh_...) are not affected. Entra mode has no shared token to rotate.
teardown.sh Deletes the Azure resource group (cascades the AKS cluster, Postgres, Azure OpenAI, ACR). Moves .env.<prefix> aside. --yes skips the confirmation prompt.

Option 3. Agentic install

Same deploy as Option 2, driven by a coding agent instead of a human operator. The agent reads the YAML, runs the scripts, watches the deploy log, and surfaces errors in context. No LLM calls inside the scripts themselves.

Claude Code

Install the private Okahu plugin (contact Okahu for the marketplace reference and install one-liner), then run:

/ok-full-deploy config/prod.yaml

The plugin exposes three slash commands: /ok-full-deploy, /ok-deploy-aks, and /ok-preflight-setup.

OpenAI Codex CLI (or any shell-driving agent)

Install the Option 2 tarball on the agent's host. Point the agent at the entry point:

./scripts/full-deploy.sh --config config/prod.yaml

Okahu provides a short reference prompt alongside the tarball that the agent uses to run the script and interpret the install log.

Support

Contact Okahu for the installer bundle, image-pull credentials, air-gapped shipments, support for additional LLM providers, and installation help.