Skip to main content
Langfuse is an open-source observability platform for LLM applications: your code sends a trace of each request, with its model calls, tokens and cost, and Langfuse stores it and shows it in a web interface. Self-hosted Langfuse 4 runs on Sevalla as two applications from the official Docker images, langfuse/langfuse (the web interface and API) and langfuse/langfuse-worker (which processes incoming traces), with a PostgreSQL database, a Redis database, a bucket in object storage, and ClickHouse as a third, private application with a disk.

At a glance

Environment variables

The langfuse and langfuse-worker applications get the same variables. Applications from a Docker image have no build, so every variable is available during runtime only. The langfuse-clickhouse application has two variables of its own:

How Langfuse runs on Sevalla

A trace travels this way: your application sends it over HTTPS to the web application, which writes the raw event to the bucket and queues a reference to it in Redis. The worker picks it up, reads the event from the bucket and writes it to ClickHouse, where the web interface reads it. Everything except the web application’s domain stays on the private network, over internal connections. The web and worker applications keep no state of their own, so each can run more than one instance (two web instances were tested). ClickHouse can’t: a process with a disk runs one instance, and Sevalla stops it before starting the new one on each of its deployments. In the tests, that took from 20 seconds to 2 minutes, and the worker dropped the traces it couldn’t write in that time. Update ClickHouse shows how to deploy it without losing traces.

Before you begin

  • A Sevalla company with a payment method: sizes above H1 and DB1 need one.
  • Python 3.11 or later on your computer, to send a test trace.
  • openssl, to generate secrets. macOS and most Linux distributions include it.
Create every service in this guide in the same Data center: internal connections work only within one location.

Create the databases and the bucket

1

Create the PostgreSQL database

In the sidebar, click Databases, then click Create database. Under Database, click PostgreSQL and choose version 17. Keep the generated credentials, enter langfuse-db as the Display name, choose the Data center and a Size, then click Create database.
2

Create the Redis database

Click Create database again. Click Redis, choose version 7.2, enter langfuse-redis as the Display name, choose the same Data center and a Size, then click Create database.
3

Create the bucket

In the sidebar, click Object storage, then click Create object storage. Enter langfuse-blobs as the Name, pick a Location and click Create object storage. On the bucket’s Settings tab, note the Endpoint, the Bucket name (for example langfuse-blobs-q8w2e), the Access key and the Secret key. See Connection values.
Langfuse 4 needs PostgreSQL 15 or later and Redis 7 or later with the noeviction memory policy. The Redis 7.2 database in the tests reported maxmemory-policy noeviction and a memory limit of 200 MB on DB1: when it’s full, Redis rejects new writes instead of dropping queued jobs. The guide was tested with DB1 for both databases; for production, Langfuse recommends 2 CPU and 4 GB of memory for PostgreSQL and 1 CPU and 1.5 GB for Redis, which DB4 and DB3 cover. See Database sizes. One bucket holds everything, in three folders: events/, media/ and exports/.

Run ClickHouse as a private application

ClickHouse isn’t a Sevalla managed database, so it runs as an application from the official image, with a disk for its data and no public traffic. Generate its password first. A hexadecimal password keeps characters that would break Langfuse’s ClickHouse connection URL out of it:
1

Create the application

In the sidebar, click Applications, then click Create > Application. Under Source, click Docker image and enter clickhouse/clickhouse-server:26.8.36.3. Keep None (public image) as the Registry credential. Enter langfuse-clickhouse as the Name, choose the Data center and the S2 size, then click Create application.
2

Add the variables

Click the Environment variables tab, then Add environment variables. Add CLICKHOUSE_USER with the value langfuse, and CLICKHOUSE_PASSWORD with the password you generated, then click Add environment variables.
3

Set the port and turn HTTP traffic off

Click the Networking tab. In Expose HTTP traffic, click Update port, enter 8123 and click Update port. Then click Disable, and Disable HTTP in the dialog.
4

Expose the native port

In Private ports, click Expose private port. Keep the web process as the Process, enter 9000 as the Port, and click Expose port.
5

Add the disk

Click the Disks tab, then Create disk. Keep the web process, enter /var/lib/clickhouse as the Path, choose 10 GB and click Create disk.
6

Deploy

Click the Overview tab, then click Deploy now under Recent deployments, and Deploy.
To check it, open the application’s Web terminal tab and run:
It prints 26.8.36.3 and UTC. Langfuse needs ClickHouse to run in UTC, which is the image’s default. Without the dashboard, run the same query with Run a command in a process (execProcessCommandV3), with the IDs from Deploy with the API:
On S2, ClickHouse used 520 MB of memory idle and at most 860 MB after storing 22,600 observations. For production, Langfuse recommends 2 CPU and 8 GB of memory, the M3 size. See Instance sizes.
The Private networking section with the Internal hostnames, Connected services and Private ports listsThe Private networking section with the Internal hostnames, Connected services and Private ports lists

Deploy the Langfuse web application

Generate the secrets

Langfuse needs three secrets. Generate each one and keep them: both Langfuse applications use the same values.

Create and connect the application

1

Create the application

In the sidebar, click Applications, then click Create > Application. Under Source, click Docker image and enter langfuse/langfuse:4.72.0. Enter langfuse as the Name, choose the same Data center and the S2 size, then click Create application. Note the domain under the application’s name, for example langfuse-x7k2m.sevalla.app.
2

Connect PostgreSQL

Click the Networking tab. Under Connected services, click Add internal connection. Choose langfuse-db as the Service and turn on Add environment variables to the application. Rename DB_URL to DATABASE_URL, then click Add internal connection.
3

Connect Redis

Click Add internal connection again. Choose langfuse-redis, turn on Add environment variables to the application, rename REDIS_PASSWORD to REDIS_AUTH, and click Add internal connection.
4

Connect ClickHouse

Click Add internal connection again. Choose langfuse-clickhouse, turn on Add environment variables to the application, rename APP_HOST to CLICKHOUSE_HOST, and click Add internal connection.
5

Add the Langfuse variables

Click the Environment variables tab, then Add environment variables. Paste the block below into the first key field, replace the placeholders, and click Add environment variables.
6

Add a readiness probe

Click the Processes tab, click ⋯ on the web process, then Update process. Under Health checks, turn on Readiness probe, set the Path to /api/public/ready, keep the Port at 8080, and click Update process.
7

Deploy

Click the Overview tab, then click Deploy now under Recent deployments, and Deploy.
.env
Langfuse also sends anonymous usage statistics to its developers. To turn that off, add TELEMETRY_ENABLED=false. When the application starts, it applies the PostgreSQL and ClickHouse migrations; on a new installation that took 15 seconds. The readiness probe keeps the instance out of traffic until Langfuse is ready, so the deployment reaches Deployed only then. Open the domain: Langfuse shows its sign-in page. The health endpoint answers without signing in:
To follow a deployment from a script, read its status with Get deployment (getDeploymentV3) until it’s success or failed, and its log with Get application deployment logs (getApplicationDeploymentLogsV3). A Docker image deployment has no build, and its log shows ✅ The image is available., then 🚀 Web has been deployed successfully. The logs operation returns the last hour unless you pass from.

Deploy the Langfuse worker

The worker uses the same variables as the web application. It serves only a health check, so it gets no public traffic.
1

Create the application

Create another application from the Docker image langfuse/langfuse-worker:4.72.0, named langfuse-worker, in the same Data center, with the S2 size.
2

Connect the three services

On its Networking tab, add an internal connection to langfuse-db, to langfuse-redis and to langfuse-clickhouse, each with Add environment variables to the application turned off.
3

Copy the variables

Open the langfuse application’s Environment variables tab and click Copy all. On the worker’s Environment variables tab, click Add environment variables, paste into the first key field, and click Add environment variables. The worker now has the same connection variables, secrets and bucket settings.
4

Turn HTTP traffic off

On the worker’s Networking tab, in Expose HTTP traffic, click Disable, then Disable HTTP.
5

Deploy

Click the Overview tab, then click Deploy now under Recent deployments, and Deploy.
The worker’s runtime logs show Listening: http://...:8080 when it’s ready. Get application runtime logs (getApplicationRuntimeLogsV3) finds the line, with WORKER_APP_ID from Deploy with the API:

Create an account and API keys

1

Sign up

Open the sign-up page, for example https://langfuse-x7k2m.sevalla.app/auth/sign-up. Enter a Name, an Email and a Password with letters, numbers and special characters, then click Sign up. Langfuse offers a newsletter; click Skip.
2

Create an organization and a project

Enter an Organization name, for example Acme, and click Create. Then enter a Project name, for example storefront, and click Create.
3

Create API keys

In the project, click Settings, then API Keys and Create new API keys. Enter a Name and click Create API key.
4

Copy the keys

The dialog shows the Secret Key, the Public Key and a .env snippet with LANGFUSE_SECRET_KEY, LANGFUSE_PUBLIC_KEY and LANGFUSE_BASE_URL. Copy them now: Langfuse shows the secret key only once.
Anyone who can open the domain can create an account until you turn sign-up off. Once your team has accounts, add AUTH_DISABLE_SIGNUP=true to the web application and deploy it: the sign-up form then answers Sign up is disabled. This also blocks invited people who don’t have an account yet, so create their accounts first.

Send a test trace

This script records a trace with a span and a generation, without calling a model, so it needs only the Langfuse keys. In an empty folder:
This installs the Langfuse Python SDK 5, which needs a Langfuse 4 server. Create the script:
trace.py
Set the three values from the API keys dialog and run it:
The script prints the trace’s address, for example https://langfuse-x7k2m.sevalla.app/project/.../traces/0f90cdc4ea1efdeee7d37a48506ae617. Open it: the trace shows the span answer-support-question with the generation draft-reply under it, 25 tokens, and the cost Langfuse calculates from its price list for claude-haiku-5-5. Tracing in the project’s sidebar lists every observation. The trace also confirms the whole path: the event file is in the bucket under events/, and the worker wrote it to ClickHouse. To check the same from a script, read the trace’s observations with Langfuse’s Observations API, with the trace ID from the address:

Trace your model calls

Langfuse’s integrations record model calls without manual spans. For the OpenAI SDK, import the client from langfuse.openai instead of openai:
openai_trace.py
Run it with pip install openai done and OPENAI_API_KEY set next to the three Langfuse variables. The trace shows an OpenAI-generation with the input and output tokens (22 and 12 in the test) and their cost. Change model to the model your application uses. For other frameworks, see Langfuse integrations.

Update Langfuse

Langfuse releases new versions often. Updates within major version 4 apply their own migrations when the web application starts; for a new major version, follow Langfuse’s upgrade guides. Keep the web and worker applications on the same version.
1

Check the backups

Take a manual backup of langfuse-db on its Backups tab. Newer versions change the database schema when they start, and the backup lets you go back.
2

Update the web application

On the langfuse application’s Settings tab, in the Source section, click Update source. Change the Docker image to the new version, for example langfuse/langfuse:4.73.0, click Update source, and deploy.
3

Update the worker

Change the worker’s image to the same version, for example langfuse/langfuse-worker:4.73.0, and deploy it.
With the readiness probe, the web application kept answering throughout its deployment in the tests: 154 requests during a redeployment all returned 200.

Update ClickHouse

A deployment of the ClickHouse application stops it, and traces the worker can’t write while it’s down are lost after 3 attempts (the worker logs ClickhouseWriter: Max attempts reached, dropped 1 events_full record(s)). Stop the worker first, so new traces wait in the Redis queue instead:
1

Stop the worker

On the worker’s Processes tab, click ⋯ on the web process, then Update process. Set Instance count to 0, click Update process, and deploy the worker.
2

Deploy ClickHouse

Change ClickHouse’s image in Update source if you’re upgrading it, then deploy the langfuse-clickhouse application, and wait for Deployed.
3

Start the worker

Set the worker’s Instance count back to 1 and deploy it.
In the test, all 20 traces sent while ClickHouse restarted this way appeared in Langfuse once the worker was back. Deploy ClickHouse this way for any change: an environment variable, a size or a new version. Check the ClickHouse versions Langfuse supports before you upgrade it.

Back up Langfuse

The bucket grows with every trace. To limit it, delete old objects under events/ on the bucket’s Objects tab; Langfuse’s blob storage guide explains how long to keep them.

Size and scale Langfuse

To run more web or worker instances, set the Instance count of their web process; Langfuse keeps sessions and queues in PostgreSQL and Redis, so any instance can answer any request. ClickHouse scales up only: give it a larger size, and grow its disk before it fills. The disk’s Usage shows on the Disks tab.

Add a custom domain

To serve Langfuse from your own domain, such as langfuse.example.com, add the domain on the web application’s Domains tab. Then set NEXTAUTH_URL to https://langfuse.example.com on both Langfuse applications and deploy them: Langfuse builds its sign-in redirects and links from NEXTAUTH_URL. Custom domains need a web process larger than H1.

Troubleshoot

Deploy with the API

This sequence deploys the same Langfuse installation with the Sevalla API, for an agent or a script. It needs:
  • An API key that can create applications, databases and object storage, in SEVALLA_API_KEY.
  • curl, jq and openssl, in a bash shell that keeps variables between commands: each step uses the IDs the earlier ones saved.
Each step saves the IDs the next ones need in shell variables. If a variable is null, its call failed: run the call again without the | jq part to read the error. The sequence also sets the LANGFUSE_INIT_* variables, Langfuse’s headless initialization: the web application creates the first user, the Acme organization, the storefront project and its API keys when it starts, so no step needs the Langfuse sign-up page. It sets the same variables as the dashboard steps, with values in place of the ${...} references. The CLI line of each step names the Sevalla CLI command, and the MCP line the Sevalla MCP server tool that does the same.
1

Pick the location

List clusters (listClustersV3) lists the locations; pick one by name:
CLI: sevalla resources clusters. MCP: get_platform_options.
2

Look up the sizes

List process resource types (listProcessResourceTypesV3), List database resource types (listDatabaseResourceTypesV3) and List disk resource types (listDiskResourceTypesV3) return the size IDs:
CLI: sevalla resources process-types, sevalla resources db-types, sevalla resources disk-types. MCP: get_platform_options.
3

Generate the secrets

The later steps put them in environment variables:
4

Create the PostgreSQL database

Create database (createDatabaseV3):
CLI: sevalla databases create --name langfuse-db --type postgresql --db-version 17 --cluster "$CLUSTER_ID" --resource-type "$DB1" --db-name langfuse --db-user langfuse --db-password "$PG_PASSWORD". MCP: create_database.
5

Create the Redis database

Create database (createDatabaseV3) again:
CLI: sevalla databases create --name langfuse-redis --type redis --db-version 7.2 --cluster "$CLUSTER_ID" --resource-type "$DB1" --db-name langfuse --db-password "$REDIS_PASSWORD". MCP: create_database.
6

Create the bucket

Create object storage bucket (createObjectStorageV3) returns the endpoint, the bucket name and the keys:
CLI: sevalla object-storage create --name langfuse-blobs. MCP: sevalla_api_create with createObjectStorageV3.
7

Create the ClickHouse application

Create application (createApplicationV3) with a Docker image source, then List processes (listProcessesV3) for its web process and internal hostname:
CLI: sevalla apps create --name langfuse-clickhouse --cluster "$CLUSTER_ID" --source dockerImage --docker-image clickhouse/clickhouse-server:26.8.36.3, then sevalla apps processes list --app-id "$CH_APP_ID". MCP: create_application with deploy: false, then get_application.
8

Set the port, turn HTTP off and set the size

Update process (updateProcessV3). is_ingress_enabled: false is the dashboard’s Disable HTTP. The API creates the web process at S1, so the size is set here:
CLI: not available for the port and HTTP traffic; sevalla apps processes update "$CH_PROCESS_ID" --app-id "$CH_APP_ID" --resource-type "$S2" sets the size. MCP: sevalla_api_update with updateProcessV3 and the same body.
9

Expose the native port

Create private port (createApplicationPrivatePortV3):
CLI: sevalla apps private-ports create "$CH_APP_ID" --process-id "$CH_PROCESS_ID" --port 9000. MCP: sevalla_api_create with createApplicationPrivatePortV3.
10

Add the disk

Attach or update process disk (updateProcessDiskV3):
CLI: sevalla apps processes disk update "$CH_PROCESS_ID" --app-id "$CH_APP_ID" --resource-type "$DISK_10GB" --mount-path /var/lib/clickhouse. MCP: sevalla_api_update with updateProcessDiskV3.
11

Add ClickHouse's variables

Create environment variable (createEnvironmentVariableV3), once per variable:
CLI: sevalla apps env-vars create "$CH_APP_ID" --key CLICKHOUSE_USER --value langfuse, once per variable. MCP: set_environment_variables.
12

Deploy ClickHouse

Trigger deployment (triggerDeploymentV3):
CLI: sevalla apps deployments trigger "$CH_APP_ID". MCP: trigger_deployment.
13

Wait for the databases

Get database (getDatabaseV3) until both are ready, then keep their internal addresses:
CLI: sevalla databases get "$PG_ID". MCP: get_database.
14

Create the web application

Create application (createApplicationV3), then List processes (listProcessesV3) and List application domains (listApplicationDomainsV3) for its address. The domain appears a moment after the application, so the last command waits for it:
CLI: sevalla apps create --name langfuse --cluster "$CLUSTER_ID" --source dockerImage --docker-image langfuse/langfuse:4.72.0, sevalla apps domains list --app-id "$WEB_APP_ID". MCP: create_application with deploy: false, then get_application.
15

Write the variables file

Both Langfuse applications get these variables. The file holds secrets: delete it at the end.
Use your own email address in LANGFUSE_INIT_USER_EMAIL: it signs in to Langfuse with ADMIN_PASSWORD.
16

Connect the web application

Create internal connection (createApplicationInternalConnectionV3) to the two databases and ClickHouse. Through the API, a connection adds no variables; the file has them.
CLI: sevalla apps internal-connections create "$WEB_APP_ID" --target-id "$PG_ID" --target-type database, once per service. MCP: sevalla_api_create with createApplicationInternalConnectionV3.
17

Add the web application's variables

Create environment variable (createEnvironmentVariableV3) for each line of both files:
It prints 41, one per variable. CLI: sevalla apps env-vars create "$WEB_APP_ID" --key <key> --value <value>, once per variable. MCP: set_environment_variables, up to 50 variables per call.
18

Set the size and the readiness probe

Update process (updateProcessV3). Send every probe field: without timeoutSeconds, the API stores 120 seconds instead of the dashboard’s 1.
CLI: sevalla apps processes update "$WEB_PROCESS_ID" --app-id "$WEB_APP_ID" --resource-type "$S2"; not available for the probe. MCP: sevalla_api_update with updateProcessV3.
19

Deploy the web application

Trigger deployment (triggerDeploymentV3), then Get deployment (getDeploymentV3) until it finishes:
It prints success. If it prints failed, read the deployment’s log with Get application deployment logs (getApplicationDeploymentLogsV3). CLI: sevalla apps deployments trigger "$WEB_APP_ID", sevalla apps deployments get "$WEB_DEPLOYMENT_ID" --app-id "$WEB_APP_ID". MCP: trigger_deployment, get_deployment, get_deployment_logs.
20

Create the worker

Create application (createApplicationV3) and List processes (listProcessesV3):
CLI: sevalla apps create --name langfuse-worker --cluster "$CLUSTER_ID" --source dockerImage --docker-image langfuse/langfuse-worker:4.72.0. MCP: create_application with deploy: false.
21

Connect the worker

Create internal connection (createApplicationInternalConnectionV3), as for the web application:
CLI: sevalla apps internal-connections create "$WORKER_APP_ID" --target-id "$PG_ID" --target-type database, once per service. MCP: sevalla_api_create with createApplicationInternalConnectionV3.
22

Add the worker's variables

Create environment variable (createEnvironmentVariableV3) for each line of langfuse.env, then delete the files:
It prints 32. CLI: sevalla apps env-vars create, once per variable. MCP: set_environment_variables.
23

Turn the worker's HTTP off and set its size

Update process (updateProcessV3):
CLI: not available for HTTP traffic; sevalla apps processes update sets the size. MCP: sevalla_api_update with updateProcessV3.
24

Deploy the worker

Trigger deployment (triggerDeploymentV3) and wait, as for the web application:
It prints success. CLI: sevalla apps deployments trigger "$WORKER_APP_ID". MCP: trigger_deployment, get_deployment.
25

Check the installation

The web application answers, the project exists, and a trace goes through the worker into ClickHouse:
trace.py is the script in Send a test trace, run in its virtual environment. A few seconds later, the Observations API returns the span and the generation from ClickHouse:
Use the trace ID that trace.py printed. Sign in to https://$LANGFUSE_HOST with LANGFUSE_INIT_USER_EMAIL and ADMIN_PASSWORD to see the trace in the interface.