Kubernetes (Helm)
This guide will walk you through the steps to deploy Langfuse on Kubernetes using the Helm package manager. You will need access to a Kubernetes cluster and Helm installed on your local machine. For the purposes of this guide, we will use a local minikube instance, but each step should extend to a managed Kubernetes service like GKE, EKS, or AKS.
If you would rather not run any infrastructure, use Langfuse Cloud: hosted by Langfuse, with a free tier and no infrastructure to run. The SDKs and integrations work identically against Langfuse Cloud and a self-hosted instance.
By default, the chart will deploy the Langfuse application containers and data stores (architecture overview). You can optionally point to an existing PostgreSQL, ClickHouse, Redis, and blob storage instance. For production, we recommend a managed blob storage service such as Amazon S3, Google Cloud Storage, or Azure Blob Storage over the bundled SeaweedFS instance. See Readme for more details.
If you are interested in contributing to our Kubernetes deployment guide or Helm chart, please create an issue on the GitHub Discussion.
Alternatively, you can use one of the following cloud-specific deployment guides:
- AWS (Terraform)
- Azure (Terraform)
- GCP (Terraform)
- Render (community)
- Railway (community)
Prerequisites
- Kubernetes
v1.28or newer, as required by the ClickHouse Kubernetes Operator. - cert-manager and the ClickHouse operator, installed once per cluster. From chart version
v2.0.0onwards,clickhouse.deploy: true(the default) rendersClickHouseClusterandKeeperClusterresources, and the operator creates cert-manager resources for its webhooks. Both CRD sets must exist beforehelm install; the chart preflights the ClickHouse CRDs and fails fast if they are missing. The Readme below lists the exact install commands.
Deployments that point every data store at an external service (*.deploy: false) do not need the operator.
Fetch the Helm chart and customize values
Fetch the langfuse-k8s Helm chart.
helm repo add langfuse https://langfuse.github.io/langfuse-k8s
helm repo updateFor local experimentation, the pre-configured variables in the values.yaml file are usually sufficient.
If you send any kind of sensitive data to the application or intend to keep it up for longer, we recommend that you modify the values.yaml file according to your needs
For a comprehensive overview of all available environment variables and configuration options, please refer to the configuration guide and the Readme.
Deploy the helm chart
Create a new namespace for the Langfuse deployment (optional), e.g.:
kubectl create namespace langfuseInstall the Helm chart into your namespace:
helm install langfuse langfuse/langfuse -n langfuseOur chart assumes that it's installed as langfuse.
If you want to install it with a different name, you will have to adjust the Redis hostname in the values.yaml accordingly.
At this point, Kubernetes will start to deploy the Langfuse application and its dependencies.
This can take up to 5 minutes.
You can monitor the progress by checking kubectl get pods -n langfuse - we expect all pods to be running eventually.
The langfuse-web and langfuse-worker container will restart a couple of times while the databases are being provisioned.
Smoke test UI
The Langfuse UI will be served on a ClusterIP service by default.
Use kubectl get services -n langfuse and search for langfuse-web to see the port mapping.
Create a port-forward via kubectl port-forward svc/langfuse-web -n langfuse <local-port>:<nodeport> and access the UI via http://localhost:<local-port> in your browser.
Go ahead and register, create a new organization, project, and explore Langfuse.
AI Gateway
The chart deploys the AI Gateway (beta) in releases after 2.2.0. Read the gateway guide for the requirements and concepts. Enable it and give it its own Ingress host in your values.yaml:
langfuse:
nextauth:
url: https://langfuse.example.com
gateway:
enabled: true
ingress:
enabled: true
className: nginx
hosts:
- gateway.langfuse.example.com
tls:
enabled: true
secretName: langfuse-gateway-tls
annotations:
# Optional: let cert-manager issue the certificate.
cert-manager.io/cluster-issuer: letsencrypt
# Streams can run for up to 600 s and stay quiet for up to 120 s.
nginx.ingress.kubernetes.io/proxy-read-timeout: "620"
nginx.ingress.kubernetes.io/proxy-send-timeout: "620"
nginx.ingress.kubernetes.io/proxy-buffering: "off"
nginx.ingress.kubernetes.io/proxy-request-buffering: "off"
# The gateway accepts request bodies of up to 16 MiB.
nginx.ingress.kubernetes.io/proxy-body-size: "17m"
resources:
requests:
cpu: "1"
memory: 2Gi
limits:
memory: 2GiApply it and check that the gateway pods become ready:
helm upgrade langfuse langfuse/langfuse -n langfuse -f values.yaml
kubectl get pods -n langfuse -l app.kubernetes.io/component=gatewayWith langfuse.gateway.enabled: true, the chart deploys the gateway as its own Deployment, Service (port 8080), Ingress, optional HorizontalPodAutoscaler, and PodDisruptionBudget. It sets LANGFUSE_AI_GATEWAY_DEPLOYED=true on web, which turns on the gateway pages for all organizations, and generates the service key and JWT private key into the <release>-app Secret. The image tag follows langfuse.image.tag; if your chart's appVersion is older than 4.75.0, set it to a newer release. If your cluster can't reach docker.langfuse.com, set langfuse.gateway.image.repository to langfuse/ai-gateway or a mirror. For all values, see the Readme.
Keys
To manage the keys yourself, for example to rotate them, create a Secret and reference it. For a release that already runs the gateway, copy the current keys from the <release>-app Secret instead of generating new ones, for example with kubectl get secret langfuse-app -n langfuse -o jsonpath='{.data.ai-gateway-service-key}' | base64 -d.
kubectl create secret generic langfuse-gateway -n langfuse \
--from-literal=ai-gateway-service-key="$(openssl rand -hex 32)" \
--from-file=ai-gateway-jwt-private-key=<(openssl ecparam -name prime256v1 -genkey -noout)langfuse:
gateway:
serviceKey:
secretKeyRef:
name: langfuse-gateway
key: ai-gateway-service-key
jwt:
privateKey:
secretKeyRef:
name: langfuse-gateway
key: ai-gateway-jwt-private-keyWith helm template-based GitOps tools such as Argo CD, the chart can't read existing Secrets, so generated keys change on every sync and gateway requests fail. Reference your own keys as shown above.
TLS
If cert-manager runs in your cluster, add its issuer annotation to the gateway Ingress. cert-manager then issues and renews a certificate for the gateway host and stores it in langfuse.gateway.ingress.tls.secretName:
langfuse:
gateway:
ingress:
enabled: true
hosts:
- gateway.langfuse.example.com
tls:
enabled: true
secretName: langfuse-gateway-tls
annotations:
cert-manager.io/cluster-issuer: letsencryptUse a langfuse.gateway.ingress.tls.secretName that differs from web's langfuse.ingress.tls.secretName, so the two certificates do not overwrite each other. With an HTTP-01 issuer, the gateway host must be reachable from the internet; for internal hosts, use a DNS-01 issuer.
Create a Kubernetes TLS Secret from your certificate and key, and reference it without a cert-manager annotation:
kubectl create secret tls langfuse-gateway-tls -n langfuse \
--cert=gateway.crt --key=gateway.keylangfuse:
gateway:
ingress:
enabled: true
hosts:
- gateway.langfuse.example.com
tls:
enabled: true
secretName: langfuse-gateway-tlsIf web's certificate already covers the gateway host, as a wildcard such as *.langfuse.example.com or as a subject alternative name, you can reference web's Secret instead. Include the full chain in gateway.crt, since clients reject certificates whose intermediates are missing.
If TLS terminates at a cloud load balancer, for example an AWS Application Load Balancer, leave langfuse.gateway.ingress.tls.enabled off and configure the certificate on the load balancer. The chart still uses https:// for the public URL when langfuse.nextauth.url is https://; otherwise set langfuse.gateway.publicUrl.
With the AWS Load Balancer Controller:
langfuse:
gateway:
ingress:
enabled: true
className: alb
hosts:
- gateway.langfuse.example.com
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]'
alb.ingress.kubernetes.io/certificate-arn: arn:aws:acm:<region>:<account>:certificate/<id>
alb.ingress.kubernetes.io/healthcheck-path: /ready
alb.ingress.kubernetes.io/load-balancer-attributes: idle_timeout.timeout_seconds=620The idle timeout applies to the whole load balancer. If the gateway shares web's load balancer through alb.ingress.kubernetes.io/group.name, the timeout changes for web too, so use a separate group for the gateway.
Public URL
The chart sets the public URL to langfuse.gateway.publicUrl or, if unset, to the first gateway Ingress host, over https:// when the Ingress has TLS or langfuse.nextauth.url is https://. Set langfuse.gateway.publicUrl when you expose the gateway another way, such as the Gateway API or a LoadBalancer Service.
Connection to web
The chart points the gateway at web's in-cluster Service, http://<release>-web.<namespace>.svc.cluster.local:3000, so this traffic stays in the cluster. If web runs elsewhere or under a custom base path, set langfuse.gateway.webUrl, with the base path if any. Across networks, use an https:// URL and let web's Ingress accept 16 MiB bodies, for example proxy-body-size: "17m".
If web's certificate is signed by a private CA, mount the bundle with langfuse.gateway.pod.extraVolumes and langfuse.gateway.pod.extraVolumeMounts, and set SSL_CERT_FILE with langfuse.gateway.pod.additionalEnv. The global langfuse.additionalEnv doesn't apply to the gateway.
Scaling
Enable langfuse.gateway.hpa.enabled and raise langfuse.gateway.hpa.minReplicas and langfuse.gateway.hpa.maxReplicas (default 1 and 2) for production traffic. See Scaling for memory sizing.
Graceful shutdown
When a pod stops, the chart waits langfuse.gateway.preStopSleepSeconds (10 s), drains for langfuse.gateway.connectionDrainTimeoutSeconds (300 s), uploads for langfuse.gateway.telemetryShutdownTimeoutSeconds (30 s), and kills the pod after langfuse.gateway.terminationGracePeriodSeconds (350 s), which must exceed the sum of the three.
Readme
Source: langfuse/langfuse-k8s
Loading README…
Features
Langfuse supports many configuration options and self-hosted features. For more details, please refer to the configuration guide.
AI Gateway (beta)
Authentication & SSO
Automated Access Provisioning
Caching
Code evaluators
Halo
Custom Base Path
Encryption
Headless Initialization
Data Masking
Networking
Organization Creators (EE)
Instance Management API (EE)
Health and Readiness Check
Observability via OpenTelemetry
Transactional Emails
UI Customization (EE)
Shutdown
You can delete the Helm release and the namespace to clean up the resources:
helm uninstall langfuse -n langfuse
kubectl delete namespace langfuseHow to Upgrade
Run the following commands to upgrade the Helm chart within a chart major version:
helm repo update
helm upgrade langfuse langfuse/langfuse -n langfuseFor more details on upgrading Langfuse itself, please refer to the upgrade guide.
Upgrade the chart from v1 to v2
Chart v2.0.0 is a major version of the Helm chart: it replaces every bundled Bitnami sub-chart with an OSS-licensed alternative. ClickHouse now runs through the ClickHouse Kubernetes Operator, PostgreSQL through groundhog2k/postgres, Valkey through valkey-io/valkey, and bundled object storage through SeaweedFS. Because StatefulSet identities and PVC layouts change, a plain helm upgrade from a v1 release that deploys any of these stores is blocked by the chart.
Follow the v1 to v2 chart upgrade guide. It covers both paths: releases that point to external stores (*.deploy: false) upgrade in place, while releases with bundled stores install a sibling v2 release, copy the data over, and then shift traffic. Your deployment must run at least Langfuse v3.224.1 before you start.
If you run the bundled ClickHouse (clickhouse.deploy: true), complete the chart v1 to v2 upgrade before you upgrade Langfuse to v4. The v1 chart cannot bring its bundled ClickHouse to the version that Langfuse v4 requires; the v2 chart can. Deployments that connect to an external ClickHouse are not affected and can upgrade Langfuse to v4 independently of the chart.
Chart v2.0.0 ships Langfuse v4 as its default appVersion. To keep the chart migration and the Langfuse v4 upgrade as two separate steps, pin langfuse.image.tag to your current Langfuse v3 image while you move to the v2 chart, then follow the v3 to v4 upgrade guide. To stay on the v1 chart for now, pass a 1.x chart version explicitly via helm upgrade --version.
If you experience any issues when self-hosting Langfuse, please:
- Check out Troubleshooting & FAQ page.
- Use Ask AI to get instant answers to your questions.
- Ask the maintainers on GitHub Discussions.
- Create a bug report or feature request on GitHub.
Enterprise-grade support is available when self-hosting Langfuse. Learn more on our pricing page.
Last updated on