This is a community-maintained repository that contains resources for deploying Langfuse on Kubernetes. Please feel free to contribute any improvements or suggestions.
Langfuse self-hosting documentation: https://langfuse.com/self-hosting
examples
directory contains exampleyaml
configurationscharts/langfuse
directory contains Helm chart for deploying Langfuse with an associated database
We provide a Helm chart that helps you deploy Langfuse on Kubernetes.
Configure the required secrets and parameters as defined below in a new values.yaml
file.
Then install the helm chart using the commands below:
helm repo add langfuse https://langfuse.github.io/langfuse-k8s
helm repo update
helm install langfuse langfuse/langfuse -f values.yaml
helm repo update
helm upgrade langfuse langfuse/langfuse
Please validate whether the helm sub-charts in the Chart.yaml were updated between versions. If yes, follow the guide for the respective sub-chart to upgrade it.
By default, the chart will run with the minimum resources to provide a stable experience. For production environments, we recommend to adjust the following parameters in the values.yaml. See Langfuse documentation for our full sizing guide.
langfuse:
resources:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "2"
memory: "4Gi"
clickhouse:
resources:
limits:
cpu: "2"
memory: "8Gi"
requests:
cpu: "2"
memory: "8Gi"
keeper:
resources:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "2"
memory: "4Gi"
redis:
primary:
resources:
limits:
cpu: "1"
memory: "1.5Gi"
requests:
cpu: "1"
memory: "1.5Gi"
s3:
resources:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "2"
memory: "4Gi"
The required configuration options to set are:
# Optional, but highly recommended. Generate via `openssl rand -hex 32`.
# langfuse:
# encryptionKey:
# value: ""
langfuse:
salt:
value: secureSalt
nextauth:
secret:
value: ""
postgresql:
auth:
# If you want to use `postgres` as the username, you need to provide postgresPassword instead of password.
username: langfuse
password: ""
clickhouse:
auth:
password: ""
redis:
auth:
password: ""
s3:
auth:
rootPassword: ""
They can alternatively set via secret references (the secrets must exist):
# Optional, but highly recommended. Generate via `openssl rand -hex 32`.
# langfuse:
# encryptionKey:
# secretKeyRef:
# name: langfuse-encryption-key-secret
# key: encryptionKey
langfuse:
salt:
secretKeyRef:
name: langfuse-general
key: salt
nextauth:
secret:
secretKeyRef:
name: langfuse-nextauth-secret
key: nextauth-secret
postgresql:
auth:
# If you want to use `postgres` as the username, you need to provide a adminPasswordKey in secretKeys.
username: langfuse
existingSecret: langfuse-postgresql-auth
secretKeys:
userPasswordKey: password
clickhouse:
auth:
existingSecret: langfuse-clickhouse-auth
existingSecretKey: password
redis:
auth:
existingSecret: langfuse-redis-auth
existingSecretPasswordKey: password
s3:
auth:
# If existingSecret is set, both root user and root password must be supplied via the secret
existingSecret: langfuse-s3-auth
rootUserSecretKey: rootUser
rootPasswordSecretKey: rootPassword
See the Helm README for a full list of all configuration options.
[...]
postgresql:
deploy: false
auth:
username: my-username
password: my-password
database: my-database
host: my-external-postgres-server.com
directUrl: postgres://my-username:my-password@my-external-postgres-server.com
shadowDatabaseUrl: postgres://my-username:my-password@my-external-postgres-server.com
[...]
s3:
deploy: false
bucket: "langfuse-bucket"
region: "eu-west-1"
endpoint: "https://s3.eu-west-1.amazonaws.com"
forcePathStyle: false
accessKeyId:
value: "mykey"
secretAccessKey:
value: "mysecret"
eventUpload:
prefix: "events/"
batchExport:
prefix: "exports/"
mediaUpload:
prefix: "media/"
[...]
langfuse:
deployment:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 50%
maxUnavailable: 50%
[...]
langfuse:
ingress:
enabled: true
hosts:
- host: langfuse.your-host.com
paths:
- path: /
pathType: Prefix
annotations: []
The Langfuse chart supports configuring storage classes for all persistent volumes in the deployment. You can configure storage classes in two ways:
- Global Storage Class: Set a global storage class that will be used for all persistent volumes unless overridden.
global:
defaultStorageClass: "your-storage-class"
- Component-specific Storage Classes: Override the storage class for specific components.
postgresql:
primary:
persistence:
storageClass: "postgres-storage-class"
redis:
primary:
persistence:
storageClass: "redis-storage-class"
clickhouse:
persistence:
storageClass: "clickhouse-storage-class"
s3:
persistence:
storageClass: "minio-storage-class"
If no storage class is specified, the cluster's default storage class will be used.
With an external Postgres server with client certificates using own secrets and additionalEnv for mappings
langfuse:
salt: null
nextauth:
secret: null
extraVolumes:
- name: db-keystore # referencing an existing secret to mount server/client certs for postgres
secret:
secretName: langfuse-postgres # contain the following files (server-ca.pem, sslidentity.pk12)
extraVolumeMounts:
- name: db-keystore
mountPath: /secrets/db-keystore # mounting the db-keystore store certs in the pod under the given path
readOnly: true
additionalEnv:
- name: DATABASE_URL # Using the certs in the url eg. postgresql://the-db-user:the-password@postgres-host:5432/langfuse?ssl=true&sslmode=require&sslcert=/secrets/db-keystore/server-ca.pem&sslidentity=/secrets/db-keystore/sslidentity.pk12&sslpassword=the-ssl-identity-pw
valueFrom:
secretKeyRef:
name: langfuse-postgres # referencing an existing secret
key: database-url
- name: NEXTAUTH_SECRET
valueFrom:
secretKeyRef:
name: langfuse-general # referencing an existing secret
key: nextauth-secret
- name: SALT
valueFrom:
secretKeyRef:
name: langfuse-general
key: salt
service:
[...]
ingress:
[...]
postgresql:
deploy: false
auth:
password: null
username: null
This example shows how to configure Okta SSO by setting the required environment variables from secrets using the additionalEnv
pattern:
langfuse:
additionalEnv:
- name: AUTH_OKTA_CLIENT_ID
valueFrom:
secretKeyRef:
name: okta-secrets
key: AUTH_OKTA_CLIENT_ID
- name: AUTH_OKTA_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: okta-secrets
key: AUTH_OKTA_CLIENT_SECRET
- name: AUTH_OKTA_ISSUER
valueFrom:
secretKeyRef:
name: okta-secrets
key: AUTH_OKTA_ISSUER
You would need to create the corresponding secret:
apiVersion: v1
kind: Secret
metadata:
name: okta-secrets
type: Opaque
stringData:
AUTH_OKTA_CLIENT_ID: "your-okta-client-id"
AUTH_OKTA_CLIENT_SECRET: "your-okta-client-secret"
AUTH_OKTA_ISSUER: "https://your-domain.okta.com"
This pattern works for any SSO provider supported by Langfuse. See the Authentication and SSO documentation for other providers and their required environment variables.
This is going to add a record to the /etc/hosts file of all containers under the langfuse-web pod in such a way that every traffic towards "oauth.id.jumpcloud.com" is going to be forwarded to the localhost network.
langfuse:
web:
hostAliases:
- ip: 127.0.0.1
hostnames:
- "oauth.id.jumpcloud.com"
Distribute pods evenly across different zones to improve high availability:
langfuse:
# Global topology spread constraints applied to all langfuse pods
pod:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app.kubernetes.io/instance: langfuse
# Component-specific topology spread constraints
web:
pod:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: web
worker:
pod:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: worker