Overview
Langfuse is an open-source LLM observability and evaluation platform: traces, prompt management, evaluations, and a playground. This template deploys the full self-hosted stack — the web app, a background worker, and the three datastores Langfuse requires — with trace data landing in an object store you own. The instance is closed by default. Self-service registration is off, and the owner account is provisioned at boot from a secret you create, so a public endpoint does not hand a stranger an account.What Gets Created
clickhouse/) and Langfuse (prefixes events/ and media/). The auth secret and, on GCS, the credentials secret are prerequisite secrets you create yourself: the chart references them by name and never creates, modifies, or deletes them.
Prerequisites
Two things must exist before you install: the auth secret, and the object storage that traces are written to.Create the auth secret
nextAuthSecret, encryptionKey and salt, and keep a copy of encryptionKey outside Control Plane. Read the values back later with cpln secret reveal AUTH_SECRET_NAME -o yaml.Set langfuse.auth.secretName to this name.Set up object storage
- AWS S3
- Google Cloud Storage
- Create an S3 bucket. Set
objectStore.aws.bucketto its name andobjectStore.aws.regionto its region. - If you do not have one, create a Cloud Account for your AWS account and set
objectStore.aws.cloudAccountNameto its name. The workloads then reach the bucket keylessly. - Create an IAM policy with the JSON below (replace
YOUR_BUCKET_NAME) and setobjectStore.aws.policyNameto its name.
Installation
Install from the marketplace registry, naming your auth secret and bucket and replacing the three bundled datastore passwords, which the chart uses exactly as written:objectStore.aws.* values with objectStore.provider=gcp, objectStore.gcp.bucket and objectStore.gcp.credentialsSecretName.
UI
CLI
Terraform
Pulumi
Configuration
Object Store
objectStore.provider is rendered into the workloads; the other is ignored.
Langfuse
langfuse.publicUrl is the origin the browser uses: auth redirects, the pages NextAuth renders server-side, and whether the session cookie gets the Secure flag all derive from it. Leave it empty unless you serve Langfuse on a custom domain, and when you set it include the scheme — a value without one is rejected at render.
With langfuse.auth.disableSignup: true (the default) the owner account from your auth secret is the only way in: Langfuse blocks both email/password sign-up and first-time SSO user creation, so the template provisions that account at boot using Langfuse’s headless initialization. Set it to false and anyone who can reach the UI can create an account and their own organization.
Access
publicAccess.enabled: false the API stays reachable from other workloads in the GVC, but there is no browser path to the UI: cpln port-forward does not reach the Langfuse web tier, so keep public access on if you need to sign in.
PostgreSQL
postgres.*, including scheduled backups — see Backing Up.
Redis
ClickHouse
Connecting
cpln workload get-deployments RELEASE_NAME-langfuse-web --gvc GVC_NAME -o yaml reports it ready:
First Run
- Open the canonical endpoint in a browser and sign in with the
adminEmailandadminPasswordfrom your auth secret. The account is anOWNERof the organization named bylangfuse.auth.organizationName, which already exists. - Create a project, then generate a key pair under Settings → API Keys.
- Send a first trace with the public ingestion API, or point a Langfuse SDK at your endpoint with the same keys:
events/ prefix of your bucket, the worker takes it off the Redis queue and writes it into ClickHouse, and the trace appears in the UI a few seconds later.
- For the playground and LLM-as-a-judge evaluations, add provider API keys under Settings → LLM Connections. They are stored encrypted with your
encryptionKey.
Operations
Backing Up
PostgreSQL is the one datastore that must be backed up: it holds users, projects, API keys, prompts, datasets and evaluation configs. ClickHouse keeps its data parts in your bucket and is as durable as that bucket — its volume set holds local metadata only. Redis holds only the transient ingestion queue and cache. Two paths cover PostgreSQL. A volume set snapshot captures the full disk state:RELEASE_NAME-postgres-backup cron workload and uploads a gzipped pg_dumpall to a bucket of your choice. It is off by default:
gcp and minio blocks — follow the postgres template’s backup prerequisites; the keys there live under postgres.backup.* here.
Restoring a Backup
These paths have not been exercised against this template; verify them on a throwaway release before relying on them.- From a scheduled dump: the dump is a plain
pg_dumpalloutput restored withpsqlagainstRELEASE_NAME-postgres.GVC_NAME.cpln.local:5432, using thepostgres.credentials.usernameandpostgres.credentials.passwordyou installed with. The command sequence per provider is on the postgres template’s restore section; it must run from a client that can reach the bucket and the database, which means a workload inside the GVC. - From a volume set snapshot:
cpln volumeset snapshot restoreexists (checkcpln volumeset snapshot restore --help) but has not been run against this template. - ClickHouse: trace data is in your bucket under
clickhouse/. A fresh ClickHouse workload pointed at the same bucket is the recovery path, but it has not been verified; deleting the bucket loses all trace history regardless of snapshots.
Upgrading from 1.0.0 or 1.0.1
Version 1.1.0 removed six values keys and moved all auth key material into the prerequisite auth secret. A values file that still carries any of them fails at render, so the upgrade aborts before anything is applied and the live release is untouched — but it does not proceed until the keys are gone. There are no compatibility fallbacks.Back up PostgreSQL
RELEASE_NAME-pg-vs before changing anything (see Backing Up).Create the prerequisite secrets
adminEmail and adminPassword have no 1.0.x equivalent — they provision the owner account.Remove the six keys and name the secrets
langfuse.auth.secretName and, on GCS, objectStore.gcp.credentialsSecretName. Replace langfuse.firewall.inboundAllowCIDR with publicAccess.enabled and internalAccess.type.Upgrade and verify
RELEASE_NAME-langfuse-web and RELEASE_NAME-langfuse-worker reach ready with cpln workload get-deployments RELEASE_NAME-langfuse-web --gvc GVC_NAME -o yaml.Upgrading from 1.1.0
Version 1.2.0 moved the bundled PostgreSQL to thepostgres 3.4.1 template, which reads its credentials from a dictionary secret. Langfuse creates that secret for you from values, so there is no new prerequisite — only a rename:
postgres.credentials.* and you are done. postgres.config.credentialsSecretName is new and names the secret the chart creates; the default is fine for a single release. The auth, Redis and ClickHouse paths are unchanged.
Upgrading from 1.2.0
Version 1.2.1 removes the AWS managed policyaws::ReadOnlyAccess from the identity this template links to your AWS cloud account. That policy granted read access to every bucket in your AWS account and contained no write actions, so it was never carrying the object store itself — but it was silently supplying any read action your bucket-scoped policy omitted. The identity now carries cpln-connector and your own policy only.
Before upgrading, update your IAM policy to the ten-action list in Prerequisites — 1.2.0 documented six actions. If it already matches, no action is needed. Nothing else changes.
Scaling and Availability
- The web tier autoscales on CPU between
langfuse.web.minReplicasandlangfuse.web.maxReplicas. Keep the minimum at 2 or more for rolling deploys without downtime. - The worker runs a fixed
langfuse.worker.replicas; raise it for higher ingestion throughput. - PostgreSQL, Redis and ClickHouse are single-instance on persistent volume sets. A node failure reschedules each and reattaches its volume, so the cost is minutes of downtime, not data loss.
- The first
helm upgradeafter an install can restart the bundled datastores even when nothing changed; plan it as a short ingestion interruption and check that traces land again afterwards rather than trusting the health endpoint, which stays green throughout. - Settings carried in the web container’s environment —
langfuse.auth.disableSignup,langfuse.publicUrl, any change to the auth secret — take effect only as the web replicas roll. Changing a value in the auth secret does not redeploy anything by itself; runcpln workload force-redeployment RELEASE_NAME-langfuse-web --gvc GVC_NAMEand the same forRELEASE_NAME-langfuse-worker.
Troubleshooting
Web and worker never become ready and cpln logs returns nothing
Web and worker never become ready and cpln logs returns nothing
cpln helm install succeeded, but RELEASE_NAME-langfuse-web and RELEASE_NAME-langfuse-worker stay not-ready with no container output. status.versions[].message reads The secret <name> no longer exists. Workload updates are paused until the secret is added or the reference to the secret removed.Cause: the secret named by langfuse.auth.secretName (or, on GCS, objectStore.gcp.credentialsSecretName) did not exist at install time.Fix: create it as shown in Prerequisites. The deployment recovers on its own after a few minutes, or force it:Install of a second release is refused as managed by a different release
Install of a second release is refused as managed by a different release
The resource 'my-langfuse-db-credentials' cannot be updated because it is being managed by a different release and creates nothing.Cause: postgres.config.credentialsSecretName names an org-wide secret, and the first release owns the default name. Nothing is shared, overwritten or deleted; the first release is unaffected.Fix: give the second release its own --set postgres.config.credentialsSecretName=... and install again.Render fails with a key was removed in 1.1.0
Render fails with a key was removed in 1.1.0
helm upgrade aborts with langfuse.auth.nextAuthSecret was removed in 1.1.0 ... (or the same for encryptionKey, salt, objectStore.gcp.accessKeyId, objectStore.gcp.secretAccessKey, langfuse.firewall.inboundAllowCIDR).Cause: your values file still carries a 1.0.x key.Fix: follow Upgrading from 1.0.0 or 1.0.1.Render fails with publicUrl must include the scheme
Render fails with publicUrl must include the scheme
langfuse.publicUrl must include the scheme, e.g. https://langfuse.example.com.Cause: langfuse.publicUrl was set to a bare hostname.Fix: prefix it with https:// (or http://).Sign-up page says registration is disabled
Sign-up page says registration is disabled
POST /api/auth/signup returns HTTP 422 with {"message":"Sign up is disabled."}.Cause: langfuse.auth.disableSignup is true, the default. This is the intended closed instance.Fix: sign in with the adminEmail / adminPassword from your auth secret and invite users from inside Langfuse, or set langfuse.auth.disableSignup: false and upgrade if you want self-service registration.Changed adminPassword in the secret but the old password still works
Changed adminPassword in the secret but the old password still works
adminPassword (or adminEmail) in the auth secret and redeployed, but the login did not change.Cause: headless initialization only creates the owner account when it does not exist yet; it does not update an existing user.Fix: change the password from inside Langfuse under the user’s settings. The values in the secret matter only for a fresh database.Database connection errors in web and worker logs on a cold install
Database connection errors in web and worker logs on a cold install
RELEASE_NAME-langfuse-web and RELEASE_NAME-langfuse-worker show Can't reach database server or Applying database migrations failed while RELEASE_NAME-postgres is still starting.Cause: startup ordering. The web and worker tiers retry and apply migrations once PostgreSQL accepts connections.Fix: none needed if the workloads reach ready. If they keep failing, check RELEASE_NAME-postgres with cpln workload get-deployments RELEASE_NAME-postgres --gvc GVC_NAME -o yaml and its logs:ClickHouse starts on GCS but object storage operations fail with an auth error
ClickHouse starts on GCS but object storage operations fail with an auth error
RELEASE_NAME-langfuse-clickhouse becomes ready, but writes to the bucket fail with an access or signature error in its logs.Cause: on the gcp path ClickHouse reads the HMAC pair from the accessKeyId and secretAccessKey keys of the secret named by objectStore.gcp.credentialsSecretName. A wrong key name, a key for a different service account, or a service account without roles/storage.objectAdmin all surface here.Fix: check the secret’s keys with cpln secret reveal GCS_CREDENTIALS_SECRET_NAME -o yaml, confirm the HMAC key belongs to the service account that was granted access, then force a redeployment:Important Notes
- Create the auth secret before installing; a missing one leaves the web and worker workloads waiting on a secret that does not exist.
encryptionKeycan never be rotated: it encrypts every provider key stored under Settings → LLM Connections, and changing it makes all of them unreadable. Keep a copy outside Control Plane and never delete the secret.- Sign-up is closed by default and the owner account comes from your secret. Record
adminPassword— it is displayed nowhere, and with sign-up closed there is no other way to create the first account. - Change
postgres.credentials.password,redis.auth.passwordandclickhouse.config.passwordbefore installing; they ship aschange-me-placeholders and are used exactly as written. - Give each install its own bucket. Two installs on one bucket share ClickHouse data parts under
clickhouse/. - Give each release its own
postgres.config.credentialsSecretName; secret names are org-wide and a second release on the default name is refused at install. - Serving Langfuse on your own domain requires
langfuse.publicUrl, including the scheme. - With
publicAccess.enabled: falsethere is no browser path to the UI; only other workloads in the GVC can reach the API. - Prerequisite secrets are not owned by the release: the auth and GCS credentials secrets survive
helm uninstalland must be deleted by hand if no longer wanted. - Uninstall deletes the volume sets, including PostgreSQL’s. Trace data already in your bucket is untouched, but users, projects and API keys are not — back up PostgreSQL first.