Skip to main content
This page is the operational counterpart to the post-install NOTES.txt that helm install langwatch ... prints, extra depth on each step plus the kubectl probes self-hosters typically run to verify the install. If you haven’t installed yet, start with helm and come back here once the chart deploys cleanly.

1. Reach the UI as the bootstrap admin

# Default service name (release name = `langwatch`)
kubectl -n langwatch port-forward svc/langwatch-app 5560:5560
open http://localhost:5560
Sign in with the email address that should own the bootstrap organization. SSO (SAML, OIDC) can be configured later, for the first sign-in any local-credential or Auth0 path is fine. If you set ingress.enabled=true and your DNS is pointing at the controller, replace the port-forward with the public URL.

2. Add at least one Model Provider credential

Personal keys reference a RoutingPolicy whose modelProviderIds[] points at one or more ModelProvider rows. Without at least one provider configured, no key, personal or service, can route traffic. In the UI: Settings → Model Providers → Add provider. Behind the scenes the chart materialises the encryption pepper needed to seal the credential at rest:
kubectl -n langwatch get secret langwatch-app-secrets \
  -o jsonpath='{.data.LW_VK_PEPPER}' | base64 -d
If the pepper rotates between deployments, previously-stored credentials become unreadable. Treat it like a database root password, bind it to your existing secret-management workflow.

3. Publish a default RoutingPolicy

In the UI: Settings → Routing Policies → New policy, scope = organization. Mark it default. Pick the providers from step 2 in your preferred fallback order. Optionally add a model allowlist — e.g. claude-3-5-* and gpt-4o*, to keep personal keys out of the expensive frontier models. When a member runs langwatch login --device, their personal VK gets bound to this policy automatically. They never see provider plumbing. If you skip this step, the CLI surfaces a clear error (policy not configured) instead of silently routing to nothing.

4. Verify the AI Gateway is healthy

# In-cluster probe via the Service
kubectl -n langwatch run curl --rm -it --image=curlimages/curl --restart=Never \
  -- curl -sS http://langwatch-gateway/healthz
# → {"status":"ok","version":"...", "uptime_s":...}

# Pod-level look at warmup + provider-cache
kubectl -n langwatch logs -l app.kubernetes.io/name=langwatch-gateway --tail 50
If the gateway can’t reach the control plane, it logs auth_upstream_unavailable and returns 503 for every VK call. The fix is almost always gateway.controlPlane.baseUrl, defaults to http://langwatch-app:5560 on the assumption your release name is langwatch. Adjust on a different release name or split-domain.

5. Expose the gateway and set its public URL

The gateway needs its own externally-reachable endpoint, separate from the app. Your LLM clients (Claude Code, Codex, Cursor) hit the gateway; the browser hits the app. So you provision two ingresses / load balancers: one for app.your-corp.com and one for gateway.your-corp.com. Then tell the control plane where the gateway lives, so it can hand that URL to CLI users at login. With the Helm chart, set the gateway’s own host and the chart derives the rest:
gateway:
  ingress:
    enabled: true
    host: gateway.your-corp.com   # your domain, not the SaaS default
  # publicUrl: https://gateway.your-corp.com   # or set explicitly
This populates LW_GATEWAY_PUBLIC_URL on the langwatch-app container. Without it, the control plane returns http://localhost:5563 to CLI users and every langwatch claude / langwatch codex call from a developer laptop fails with Cannot reach AI Gateway ... fetch failed. Do NOT reuse LW_GATEWAY_BASE_URL for this — that variable is the internal control-plane URL the Go gateway dials back on, a different direction. Verify it landed:
kubectl -n langwatch get deploy langwatch-app -o jsonpath='{.spec.template.spec.containers[0].env[?(@.name=="LW_GATEWAY_PUBLIC_URL")].value}'
# → https://gateway.your-corp.com
For the admin-side walkthrough of features (RoutingPolicies, budgets, off-boarding policy), see admin setup under the governance section, same content, audience is the admin not the operator.