Skip to content

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. List the ingress endpoints your ingress controller has provisioned:

    Terminal window
    kubectl get ingress -A

    Each 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 ADDRESS
    api api-ingress nginx api.kindo.example.com 203.0.113.10
    next next-ingress nginx app.kindo.example.com 203.0.113.10
    superadmin superadmin-ingress nginx superadmin.kindo.example.com 203.0.113.10
  2. Create DNS records for every hostname under your base domain. Either publish a wildcard or explicit records. kindo ingress manifest lists every host.

    Wildcard (simplest):

    *.kindo.example.com A 203.0.113.10

    If 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):

    HostBackend servicePortHealth checkAccess
    app.kindo.example.comnext80/api/_healthAllowlisted (users)
    api.kindo.example.comapi80/healthcheckAllowlisted (users + frontend); /webhook public unless a dedicated webhooks hostname is set
    integrations-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)
  3. Wait for propagation, then confirm from outside the cluster:

    Terminal window
    dig +short app.kindo.example.com
    dig +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’s proxy_buffering off plus generous proxy_read_timeout / proxy_send_timeout. In Traefik set respondingTimeouts; in Envoy set stream_idle_timeout. Default buffering and 60s timeouts truncate chat responses.
  • Hatchet path-based routing on hatchet.<domain>: route /api/* to hatchet-api with 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 /auth and /superadmin to api ahead of / to superadmin. Match /auth and /superadmin as path segments. With an AWS ALB IngressGroup, give the api rules the lower group.order.

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.

  1. 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 --overwrite

    Or create a single Certificate resource that covers every Kindo host and reference its secret from each ingress’s tls: block.

  2. Verify certificate issuance:

    Terminal window
    kubectl get certificate -A
    kubectl describe certificate <name> -n <namespace>
  1. 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
  2. Reference the secret from each ingress. The secret name must match what the ingress tls.secretName references. 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”
  1. Store the superadmin key. The superadmin-bootstrap step 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.

  2. Sign in to the superadmin dashboard. Open https://superadmin.<domain>, enter the email you set as operatorEmail, select Continue, then select Email me a code. Enter the 6-digit code from the email.

  3. 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.

  4. 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.

  5. 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.

  6. 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.

  7. Run the smoke test. Complete the smoke test to confirm users can sign in and chat.

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.

Terminal window
kindo config override set next NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN=false NEXT_PUBLIC_ENABLE_EMAIL_OTP_LOGIN=false
kindo config override apply next

On an install that delivers secrets from an external store, kindo config override refuses to run. Set the same keys as chart values:

Terminal window
kindo config helm-override set next envData.NEXT_PUBLIC_ENABLE_GOOGLE_LOGIN=false envData.NEXT_PUBLIC_ENABLE_EMAIL_OTP_LOGIN=false
kindo config helm-override apply next

To 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:

Terminal window
kindo config helm-override set superadmin config.enableGoogleLogin=false config.enableEmailOtpLogin=false
kindo config helm-override apply superadmin

With 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):

Terminal window
kindo config helm-override unset superadmin config.enableEmailOtpLogin
kindo config helm-override apply superadmin
Terminal window
kindo status

Every step should show completed, and the Superadmin: line should show ✓ bootstrapped. The integrations step may show failed; resolve its error and re-run it:

Terminal window
kindo install --step integrations

If another step failed, resolve its error and resume:

Terminal window
kindo install --resume
Terminal window
kubectl get pods -A --field-selector=status.phase!=Running,status.phase!=Succeeded

Expect an empty list, or only pods still starting. Check each release’s health in the live release table from kindo status.

Terminal window
curl -fsS https://api.kindo.example.com/healthcheck

Expected: 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).

  1. Open https://app.kindo.example.com in a private window.
  2. 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.
  3. Send a short message to the default model.
  4. Confirm the response streams back. If it arrives as a single chunk, your ingress is buffering. Revisit the routing requirements.