LLM Observability
    Tracing

    Deploy Langfuse on a VPS

    Self-host Langfuse LLM observability and tracing on a RamNode VPS with Docker Compose, Postgres, ClickHouse, Redis, and nginx TLS.

    Langfuse is an LLM observability/tracing platform (self-hosted alternative to hosted Langfuse Cloud). The self-hosted stack is Postgres + ClickHouse + Redis + MinIO (or S3-compatible storage) + the Langfuse web/worker containers. It's lighter than a full RAG stack but still needs a proper mid-tier VPS.

    1. Prerequisites

    • RamNode VPS on Ubuntu 24.04 LTS
    • Minimum 8 GB RAM, 2-4 vCPUs, 40 GB disk (ClickHouse is the main RAM consumer; give it headroom if you expect high trace volume)
    • DNS A record for the subdomain, e.g. langfuse.yourdomain.com
    • Root/sudo SSH access

    2. Base server setup

    shell
    apt update && apt -y upgrade
    apt -y install curl git ufw
    
    ufw allow OpenSSH
    ufw allow 80/tcp
    ufw allow 443/tcp
    ufw enable

    3. Install Docker

    shell
    curl -fsSL https://get.docker.com | sh
    apt -y install docker-compose-plugin
    systemctl enable --now docker

    4. Clone Langfuse and configure environment

    shell
    git clone https://github.com/langfuse/langfuse.git /opt/langfuse
    cd /opt/langfuse
    cp .env.example .env

    Edit .env — required values before first boot:

    • NEXTAUTH_SECRET — generate with openssl rand -base64 32
    • SALT — generate with openssl rand -base64 32
    • ENCRYPTION_KEY — generate with openssl rand -hex 32
    • NEXTAUTH_URL — set to https://langfuse.yourdomain.com
    • POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, MINIO_ROOT_PASSWORD — strong unique values, not the sample defaults
    • LANGFUSE_INIT_ORG_ID / LANGFUSE_INIT_PROJECT_ID / LANGFUSE_INIT_USER_EMAIL / LANGFUSE_INIT_USER_PASSWORD — optional but convenient: bootstraps an org, project, and admin user on first startup so you skip the manual setup wizard

    If you'd rather use RamNode's object storage or another S3-compatible bucket instead of the bundled MinIO, set the LANGFUSE_S3_* variables and drop the minio service from the compose file — fewer moving parts to maintain long-term.

    5. Start the stack

    shell
    docker compose up -d

    This brings up Postgres, ClickHouse, Redis, MinIO (if kept), and the Langfuse web + worker containers. Tail logs until healthy:

    shell
    docker compose logs -f langfuse-web

    The web container listens on port 3000 by default.

    6. nginx reverse proxy + TLS

    shell
    apt -y install nginx certbot python3-certbot-nginx

    /etc/nginx/sites-available/langfuse:

    shell
    server {
        listen 80;
        server_name langfuse.yourdomain.com;
    
        location / {
            proxy_pass http://127.0.0.1:3000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";   # Langfuse uses websockets for live trace updates
        }
    }
    shell
    ln -s /etc/nginx/sites-available/langfuse /etc/nginx/sites-enabled/
    nginx -t && systemctl reload nginx
    certbot --nginx -d langfuse.yourdomain.com

    7. First login

    Go to https://langfuse.yourdomain.com. If you set the LANGFUSE_INIT_* variables, log in directly with that admin account; otherwise complete the sign-up wizard for the first org/project. From Project Settings → API Keys, generate the public/secret key pair your applications will use to send traces (via the Langfuse SDK or OpenTelemetry).

    8. Backups

    Two datastores matter most:

    • Postgres — holds users, projects, API keys, config
    • ClickHouse — holds the actual trace/observation data (this grows fastest)
    shell
    # Postgres
    docker exec langfuse-postgres-1 pg_dump -U postgres postgres > /root/backups/langfuse-pg-$(date +%F).sql
    
    # ClickHouse (native backup, or dump via clickhouse-client depending on version)
    docker exec langfuse-clickhouse-1 clickhouse-client --query "BACKUP DATABASE default TO Disk('backups', 'langfuse-ch-$(date +%F)')"

    Ship both off-box on a schedule (cron + rsync/rclone to another RamNode instance or object storage).

    9. Updating

    shell
    cd /opt/langfuse
    docker compose down
    git pull
    docker compose pull
    docker compose up -d

    Check the migration notes in release changelogs — ClickHouse schema migrations run automatically on startup but can take time on large datasets; don't kill the container mid-migration.

    Troubleshooting notes

    • ClickHouse container OOM-killed on boot → bump VPS RAM or lower ClickHouse's memory limits in the compose file; it's the single biggest consumer here.
    • "Invalid NEXTAUTH_URL" errors → this must exactly match the public HTTPS URL, including scheme, or auth callbacks fail.
    • Traces not appearing → check the SDK is pointed at the right host and using the correct public/secret key pair for the project, and confirm the langfuse-worker container (not just langfuse-web) is healthy — ingestion is processed asynchronously by the worker.