Skip to content

Getting started

  • A Nebari cluster with nebari-operator v0.1.0-alpha.19 or later
  • cert-manager, able to issue certificates for your domain
  • Envoy Gateway (the NebariApp routes through it)
  • Keycloak, reachable — the operator provisions an OIDC client
  • Helm 3
  • The target namespace opted in:
    Terminal window
    kubectl label namespace langfuse nebari.dev/managed=true

Enough cluster capacity for four datastores. ClickHouse in particular is not small — see Datastores.

Without a Nebari platform, go to Standalone deployment.

Terminal window
helm repo add nebari https://nebari-dev.github.io/helm-repository
helm repo update
# examples/ ships in the pack repository, not inside the published chart
git clone https://github.com/nebari-dev/langfuse-pack.git
cd langfuse-pack
helm install langfuse nebari/nebari-langfuse \
-f examples/nebari-values.yaml \
--set nebariapp.hostname=langfuse.example.com \
--set langfuse.langfuse.nextauth.url=https://langfuse.example.com \
--set langfuse.langfuse.auth.providers.keycloak.issuer=https://keycloak.example.com/realms/nebari \
--namespace langfuse

The upstream langfuse/langfuse chart comes in as a transitive dependency — only the Nebari repo needs adding.

None of these have usable defaults, and two of them fail in ways that do not point at themselves.

ValueMust be
nebariapp.hostnameyour FQDN
langfuse.langfuse.nextauth.urlhttps://<same hostname>
langfuse.langfuse.auth.providers.keycloak.issuerhttps://<keycloak>/realms/<realm>

nextauth.url defaults to http://localhost:3000. Leave it and NextAuth builds callback URLs pointing at localhost — the login round-trip fails after Keycloak, not before, which makes it look like a Keycloak problem.

issuer defaults to the literal https://REPLACE-ME/realms/nebari. Langfuse requires AUTH_KEYCLOAK_ISSUER, and the OIDC secret’s issuer-url key is populated only when the operator has KEYCLOAK_EXTERNAL_URL set — on most clusters it is empty, so the value cannot be read automatically. Sub-chart values cannot be templated from the parent, which is why the chart cannot derive it from nebariapp.hostname either.

clientId and clientSecret are automatic — they come from the langfuse-oidc-client Secret the operator creates.

WorkloadPurpose
langfuse-webUI and API, port 3000
langfuse-workerAsync ingestion and processing
langfuse-postgresqlMetadata
langfuse-clickhouse-shard0Traces, observations, scores
langfuse-redis-primaryQueue and cache
langfuse-s3Large payload storage
langfuse-secretsGenerated credentials
langfuseNebariApp

Two of those names are not what you would guess. MinIO comes in under the upstream alias s3, so every one of its resources is langfuse-s3 — there is nothing named langfuse-minio. Redis is the Valkey chart aliased to redis, so the StatefulSet is langfuse-redis-primary. ClickHouse’s Service is langfuse-clickhouse while its StatefulSet carries the shard suffix.

Terminal window
kubectl -n langfuse get pods
kubectl -n langfuse get nebariapp,httproute,certificate
# Langfuse's own health endpoint — note the path
kubectl -n langfuse port-forward svc/langfuse-web 3000:3000 &
curl -sf http://localhost:3000/api/public/health && echo OK
kill %1

The health path is /api/public/health, not /health. The landing-page tile’s health check is configured for it; anything else you point at Langfuse should be too.

First start takes a while — Langfuse runs schema migrations against PostgreSQL and ClickHouse before langfuse-web becomes ready.

Open https://langfuse.example.com. Keycloak takes the login, and Langfuse creates the account on first sign-in.

disableUsernamePassword: true is the default here, so the email/password form is gone and SSO is the only way in.