Configure & Validate
After kindo install --apply finishes, take the deployment from running pods to users signing in: publish DNS, terminate TLS, sign in to the superadmin dashboard, create the first organization and its SSO, and run a smoke test.
1. Publish DNS records
Section titled “1. Publish DNS records”-
List the ingress endpoints your ingress controller has provisioned:
Terminal window kubectl get ingress -AEach ingress shows the external IP address or hostname of your ingress load balancer, usually the same one for every Kindo host. Example output:
NAMESPACE NAME CLASS HOSTS ADDRESSapi api-ingress nginx api.kindo.example.com 203.0.113.10next next-ingress nginx app.kindo.example.com 203.0.113.10superadmin superadmin-ingress nginx superadmin.kindo.example.com 203.0.113.10 -
Create DNS records for every hostname under your base domain. Either publish a wildcard or explicit records.
kindo ingress manifestlists every host.Wildcard (simplest):
*.kindo.example.com A 203.0.113.10If the load balancer has a hostname instead of an IP address, use a CNAME record pointing at it.
Explicit (when you need per-host firewall rules, specific target ports, or custom health checks):
Host Backend service Port Health check Access app.kindo.example.comnext80 /api/_healthAllowlisted (users) api.kindo.example.comapi80 /healthcheckAllowlisted (users + frontend); /webhookpublic unless a dedicated webhooks hostname is setintegrations-api.kindo.example.comnango80 /healthPublic (integration OAuth callbacks) integrations-connect.kindo.example.comnango-connect-ui3009 /Allowlisted unleash.kindo.example.comunleash4242 /healthAllowlisted unleash-edge.kindo.example.comunleash-edge3063 /internal-backstage/readyAllowlisted hatchet.kindo.example.com(/api/*)hatchet-api8080 /api/readyAllowlisted (task worker traffic) hatchet.kindo.example.com(/*)hatchet-frontend8080 /api/readyAllowlisted (admin UI) hyperdx.kindo.example.comhyperdx3000 /api/healthAllowlisted (your team) superadmin.kindo.example.com(/auth,/superadmin)api80 /healthcheckAllowlisted (your team) superadmin.kindo.example.com(/)superadmin80 /healthAllowlisted (your team) -
Wait for propagation, then confirm from outside the cluster:
Terminal window dig +short app.kindo.example.comdig +short api.kindo.example.com
Routing requirements that can’t be left at defaults
Section titled “Routing requirements that can’t be left at defaults”Configure these routes and settings on your ingress controller or WAF:
- Server-Sent Events on
/express/chat: the API streams chat responses as SSE. Your ingress must disable response buffering, allow read/send timeouts ≥ 300s, allow unlimited response body size, and preserve response content. In NGINX that’sproxy_buffering offplus generousproxy_read_timeout/proxy_send_timeout. In Traefik setrespondingTimeouts; in Envoy setstream_idle_timeout. Default buffering and 60s timeouts truncate chat responses. - Hatchet path-based routing on
hatchet.<domain>: route/api/*tohatchet-apiwith higher priority than/*, which routes to the admin UI (hatchet-frontend). - AWS Load Balancer Controller with a non-VPC CNI: see Provider notes.
- Superadmin dashboard routing on
superadmin.<domain>: route/authand/superadmintoapiahead of/tosuperadmin. Match/authand/superadminas path segments. With an AWS ALB IngressGroup, give theapirules the lowergroup.order.
2. Terminate TLS at the ingress
Section titled “2. Terminate TLS at the ingress”If the contract’s ingress: block is enabled, the CLI renders every Ingress object and TLS follows ingress.tls.mode: acm, cert-manager, secret, or none. Follow this section when you route the hosts yourself (kindo ingress manifest lists them).
Choose one of the following options.
Option A: cert-manager (recommended)
Section titled “Option A: cert-manager (recommended)”-
Request certificates. With cert-manager and a
ClusterIssuer(Let’s Encrypt, private CA, Vault, etc.) installed, annotate each Ingress you created:Terminal window kubectl annotate ingress <name> -n <namespace> cert-manager.io/cluster-issuer=letsencrypt-prod --overwriteOr create a single
Certificateresource that covers every Kindo host and reference its secret from each ingress’stls:block. -
Verify certificate issuance:
Terminal window kubectl get certificate -Akubectl describe certificate <name> -n <namespace>
Option B: manual certs
Section titled “Option B: manual certs”-
Create Kubernetes TLS secrets from certs issued by your private CA or certificate vendor:
Terminal window kubectl create secret tls kindo-tls \-n <namespace> \--cert=tls.crt \--key=tls.key -
Reference the secret from each ingress. The secret name must match what the ingress
tls.secretNamereferences. If you use one wildcard cert for all hosts, create the secret in each ingress’s namespace (or use a tool like reflector to replicate it).
3. Sign in and set up the first organization
Section titled “3. Sign in and set up the first organization”-
Store the superadmin key. The
superadmin-bootstrapstep prints your key once. Store it in your secret manager immediately. Keys expire after 90 days by default. Replace a lost or expiring key from the superadmin dashboard under Keys > New key. -
Sign in to the superadmin dashboard. Open
https://superadmin.<domain>, enter the email you set asoperatorEmail, select Continue, then select Email me a code. Enter the 6-digit code from the email. -
Create the organization. Open Organizations > Create organization and fill in Organization name, First administrator email, and Domains. The first administrator email becomes the organization’s Admin.
-
Verify its domain. Verify ownership of the domain yourself, then open the organization’s Domains tab > Edit domains, turn on Verified for the domain, and select Save domains. The dashboard records your assertion. SSO requires at least one verified domain.
-
Impersonate an Admin. In the organization’s Users tab, open an active Admin user’s actions menu and select Impersonate… > Prepare session > Open customer app. The session grants full Admin access for one hour. Actions are audited as that user and attributed to you. Use a separate browser profile to keep an existing app sign-in; opening the customer app replaces the app sign-in in that browser profile.
-
Set up SSO in the app. Open Settings > SSO and select Create SAML connection. Follow SSO Setup for the connection and IdP steps. For an install upgraded from 2026.07, see Restore SSO for each organization.
-
Run the smoke test. Complete the smoke test to confirm users can sign in and chat.
4. Limit the sign-in methods shown
Section titled “4. Limit the sign-in methods shown”The app’s /login offers SAML SSO, an emailed one-time code, and, once configured, Google. To offer SAML only, or SAML plus one of the others, hide the other methods. The toggles control button visibility; the API routes remain available.
The toggles are env vars on the next release. A method is hidden only when the value is false (case-insensitive, surrounding whitespace ignored); unset means shown. Google is set to false by default. To offer it, set GOOGLE_OAUTH_CLIENT_ID and GOOGLE_OAUTH_CLIENT_SECRET on the api release, then set NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN=true.
kindo config override set next NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN=false NEXT_PUBLIC_ENABLE_EMAIL_OTP_LOGIN=falsekindo config override apply nextOn an install that delivers secrets from an external store, kindo config override refuses to run. Set the same keys as chart values:
kindo config helm-override set next envData.NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN=false envData.NEXT_PUBLIC_ENABLE_EMAIL_OTP_LOGIN=falsekindo config helm-override apply nextTo bring a method back, remove the override with kindo config override unset next <KEY> or kindo config helm-override unset next <path> and re-run the matching apply. For Google, set the key to true instead.
The superadmin dashboard offers SSO to superadmins whose organization has an SSO connection. Google is hidden there by default too; set config.enableGoogleLogin=true to offer it. To hide Google and emailed-code sign-in on the dashboard, set both toggles to false:
kindo config helm-override set superadmin config.enableGoogleLogin=false config.enableEmailOtpLogin=falsekindo config helm-override apply superadminWith both toggles off, dashboard sign-in requires an SSO connection for the superadmin’s organization. A superadmin whose organization lacks a connection sees an error.
To bring emailed-code sign-in back, unset its key and re-run the apply (for Google, set its key to true instead):
kindo config helm-override unset superadmin config.enableEmailOtpLoginkindo config helm-override apply superadmin5. Smoke test
Section titled “5. Smoke test”5.1 Install state from the CLI
Section titled “5.1 Install state from the CLI”kindo statusEvery step should show completed, and the Superadmin: line should show ✓ bootstrapped. The integrations step may show failed; resolve its error and re-run it:
kindo install --step integrationsIf another step failed, resolve its error and resume:
kindo install --resume5.2 Pod health
Section titled “5.2 Pod health”kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=SucceededExpect an empty list, or only pods still starting. Check each release’s health in the live release table from kindo status.
5.3 API health check
Section titled “5.3 API health check”curl -fsS https://api.kindo.example.com/healthcheckExpected: HTTP 200. If TLS fails, rerun the cert-manager verification from step 2. If you get a 502 / 504, check the API pod logs (kubectl logs -n api -l app.kubernetes.io/name=api).
5.4 Manual chat test
Section titled “5.4 Manual chat test”- Open
https://app.kindo.example.comin a private window. - Sign in as a user of the organization, using SSO once it is live, or an emailed code at
https://app.kindo.example.com/login. - Send a short message to the default model.
- Confirm the response streams back. If it arrives as a single chunk, your ingress is buffering. Revisit the routing requirements.
