MAATRIX / Блог / Как установить и настроить Langfuse на VPS

Как установить и настроить Langfuse на VPS

Как установить и настроить Langfuse на VPS

MAATRIX

Приложение дёргает GPT-4o или Claude по несколько раз ради одного ответа, а когда результат получается странным — виден только финальный текст, без зацепки, какой промпт ушёл на каком шаге и сколько это стоило. Langfuse закрывает эту дыру: трассировка каждого вызова модели, промпт-менеджмент и учёт стоимости в одном интерфейсе на вашем сервере. Разбираем установку на VPS через Docker Compose — шесть сервисов, headless-инициализация без единого клика в браузере и первая трасса за пятнадцать минут.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Что такое Langfuse и когда его действительно стоит поднимать

Langfuse — open-source платформа LLM-observability: перехватывает вызовы к моделям и агентские цепочки, раскладывает их на трейсы с вложенными шагами (span, generation), считает токены и стоимость по вашим тарифам, хранит промпты отдельно от кода как версионируемые сущности. Видно, какой шаг в цепочке из пяти вызовов вернул мусор, сколько стоил диалог конкретного пользователя, и можно откатить промпт к прошлой версии без деплоя.

Архитектура объясняет всё остальное в статье. Это не один процесс, а связка из шести сервисов:

СервисРольПочему нельзя выкинуть
langfuse-webUI и приём запросов от SDKбез неё нет ни интерфейса, ни API
langfuse-workerасинхронная обработка очередипишет трейсы в ClickHouse, гоняет батч-экспорт
PostgreSQLорганизации, проекты, ключи, промптына них держится авторизация
ClickHouseсами трейсы, спаны, оценкиколоночная СУБД — держит быстрые дашборды на миллионах записей
Redisочередь приёма и кэшбуфер между SDK и ClickHouse обязателен
S3-хранилище (MinIO)сырые события, медиа, экспортынекуда класть входящие данные до разбора воркером

Заметно тяжелее LiteLLM или Ollama, которые поднимаются одним контейнером — честная плата за то, что дашборды по миллионам трейсов строятся за секунду, а не собираются грепом по логам.

Когда Langfuse не нужен: один системный промпт и десяток запросов в день — весь стек избыточен, хватит логов в файл. Окупается там, где несколько промптов в проде, агентские цепочки с ветвлением, нужен учёт стоимости в разрезе клиента или фичи, а на споры «модель сегодня отвечает хуже» трейсы отвечают фактами, а не ощущениями.

Что подготовить на VPS: ОС, ресурсы, локация

Система — Ubuntu 24.04 LTS или Debian 12, из софта нужен только Docker с плагином compose:

curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker compose version
# Docker Compose version v2.39.4

Дальше — реальная оценка ресурсов, не на глаз. Документация проекта для развёртывания через docker-compose на одной машине называет ориентир от 4 ядер, 16 ГБ RAM и 100 ГБ диска — не наш замер, а рекомендация самого проекта для связки из шести сервисов на одном хосте. Цифра заметно больше, чем у LiteLLM или vLLM из этой же серии: там один процесс, здесь СУБД, колоночная аналитическая база, очередь и объектное хранилище плюс два приложения поверх. Диск нужен с запасом — основной объём набирает не Postgres, а ClickHouse, подробный расчёт в материале сколько RAM нужно для Langfuse.

Логика локации здесь другая, чем в статьях про инференс: Langfuse сам никуда не стучится к OpenAI или Anthropic, он принимает данные от вашего приложения. А в трейсы попадает содержимое промптов и ответов — если приложение работает с пользователями из ЕС или Британии, это персональные данные в смысле GDPR, и юрисдикция хранения встаёт раньше вопроса задержки. Поэтому логичнее Великобритания: вне периметра 152-ФЗ и в понятной для европейской аудитории юрисдикции.

Фаервол — база до первого контейнера:

ufw allow 22/tcp
ufw allow 80,443/tcp
ufw enable

Порт самого Langfuse откроем позже осознанно — там есть нюанс, специфичный именно для этого стека.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Langfuse

Установка через Docker Compose: реальные шаги

Официальный путь — клонировать репозиторий, он же и есть дистрибутив:

mkdir -p /opt/langfuse && cd /opt/langfuse
git clone --depth 1 https://github.com/langfuse/langfuse.git .

В docker-compose.yml — те же шесть сервисов, с конкретными образами: docker.langfuse.com/langfuse/langfuse:4 и docker.langfuse.com/langfuse/langfuse-worker:4, clickhouse/clickhouse-server:25.12, postgres:17, redis:7, cgr.dev/chainguard/minio. Секретные значения помечены комментарием # CHANGEME: SALT=mysalt, ENCRYPTION_KEY из 64 нулей, CLICKHOUSE_PASSWORD=clickhouse, POSTGRES_PASSWORD=postgres, REDIS_AUTH=myredissecret, MINIO_ROOT_PASSWORD=miniosecret. Оставите как есть — получите Langfuse, который работает одинаково у всех, кто скачал тот же файл.

Сам compose не редактируем — рядом кладём .env, Docker Compose подхватит его сам:

PG_PASS=$(openssl rand -hex 16)
cat > .env <<EOF
POSTGRES_PASSWORD=$PG_PASS
DATABASE_URL=postgresql://postgres:$PG_PASS@postgres:5432/postgres
SALT=$(openssl rand -base64 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
NEXTAUTH_SECRET=$(openssl rand -base64 32)
NEXTAUTH_URL=https://langfuse.example.com
CLICKHOUSE_PASSWORD=$(openssl rand -hex 16)
REDIS_AUTH=$(openssl rand -hex 16)
MINIO_ROOT_PASSWORD=$(openssl rand -hex 16)
EOF
chmod 600 .env

Неочевидная ловушка: часть переменных не связана шаблоном, синхронизировать их надо руками. POSTGRES_PASSWORD — пароль контейнера Postgres, а DATABASE_URL у langfuse-web и langfuse-worker — отдельная строка со своим дефолтом; поменяли одно и забыли другое — в логах воркера будет password authentication failed for user "postgres". То же с MinIO: MINIO_ROOT_PASSWORD — пароль самого MinIO, а LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, ..._MEDIA_UPLOAD_SECRET_ACCESS_KEY и ..._BATCH_EXPORT_SECRET_ACCESS_KEY — три независимые переменные для доступа к нему как к S3; все три должны совпасть с новым паролем, иначе сохранение медиа и экспортов упадёт молча.

ENCRYPTION_KEY требователен: ровно 64 символа, только 0-9a-f. Иначе langfuse-web откажется стартовать — видно в docker compose logs langfuse-web как ошибку валидации. openssl rand -hex 32 всегда даёт корректный формат.

ClickHouse и Postgres обязаны жить в UTC — иначе дашборды тихо показывают не те данные или пустые графики; в compose это уже учтено (TZ: UTC, PGTZ: UTC), проверьте только, что хост не переопределяет таймзону чем-то ещё.

Запуск и первая проверка:

docker compose up -d
docker compose ps
curl -s http://127.0.0.1:3000/api/public/health
# {"status":"OK","version":"4.24.0"}

Подъём занимает две-три минуты — ClickHouse накатывает миграции. У проверки есть ещё два флага: ?failIfDatabaseUnavailable=true дополнительно дёргает Postgres, а ?failIfNoRecentEvents=true — если давно не было ни одного трейса: алерт на «данные перестали доходить», а не только на «контейнер упал».

Первая организация, проект и ключи: через интерфейс или headless

После docker compose up -d открываем http://ваш-ip:3000 (или домен, если уже настроен обратный прокси — следующий раздел). Первый созданный аккаунт автоматически становится владельцем организации: регистрация открыта для любого, кто дотянется до порта 3000. Сразу после создания первого пользователя закройте её:

echo 'AUTH_DISABLE_SIGNUP=true' >> .env
docker compose up -d

Второй путь — headless-инициализация, без единого клика в браузере: если до первого запуска положить в .env набор LANGFUSE_INIT_*, Langfuse сам создаст организацию, проект, пользователя и пару ключей:

LANGFUSE_INIT_ORG_ID=maatrix
LANGFUSE_INIT_ORG_NAME=MAATRIX
LANGFUSE_INIT_PROJECT_ID=default
LANGFUSE_INIT_PROJECT_NAME=production
LANGFUSE_INIT_PROJECT_PUBLIC_KEY=pk-lf-...
LANGFUSE_INIT_PROJECT_SECRET_KEY=sk-lf-...
LANGFUSE_INIT_USER_EMAIL=admin@example.com
LANGFUSE_INIT_USER_NAME=Admin
LANGFUSE_INIT_USER_PASSWORD=...

Единственная ловушка — не оборачивайте значения в кавычки: Docker Compose передаёт их в контейнер буквально, вместе с символами ".

Через интерфейс ключи смотрите в Settings → API Keys — публичный pk-lf-... и секретный sk-lf-..., пара на каждый проект. Секретный ключ показывается один раз: потеряли — выпускайте новый и обновляйте его в приложении.

Подключаем приложение: Python SDK и первая трасса

SDK ставится штатно:

pip install langfuse

Актуальная версия на момент подготовки статьи — 4.15.1, релизы выходят почти ежедневно: 27 августа — 4.14.6 и 4.15.0, 28-го — 4.15.1. Фиксируйте версию в requirements.txt, а не берите последнюю вслепую перед деплоем.

Три переменные окружения — и SDK знает, куда слать данные:

export LANGFUSE_PUBLIC_KEY=pk-lf-...
export LANGFUSE_SECRET_KEY=sk-lf-...
export LANGFUSE_BASE_URL=https://langfuse.example.com

В старых туториалах встретите LANGFUSE_HOST — прежнее имя той же переменной, SDK читает её для обратной совместимости, но текущая документация везде использует LANGFUSE_BASE_URL.

Минимальный пример — генерация, обёрнутая в трассу:

from langfuse import get_client

langfuse = get_client()

with langfuse.start_as_current_observation(
    as_type="generation", name="chat-reply", model="gpt-4o-mini"
) as gen:
    # здесь вызов вашей модели
    gen.update(output="Привет! Чем помочь?")

langfuse.flush()

flush() обязателен для одноразовых скриптов: SDK шлёт данные фоном асинхронно, и если процесс завершится раньше, очередь уйдёт вместе с ним. В веб-приложении фоновый флаш и так срабатывает по таймеру.

Для тех, у кого рядом уже стоит шлюз LiteLLM: трейсить каждый вызов можно вообще без SDK в коде приложения.

litellm_settings:
  success_callback: ["langfuse"]

Те же три переменные окружения — и шлюз сам шлёт трейс на каждый запрос.

Трассу в разделе Traces увидите не мгновенно: событие уходит в очередь на Redis, потом воркер разбирает её в ClickHouse. Если проходит несколько минут, а трасс всё нет и ошибок в логах тоже — разбор отдельный: Langfuse не видит трейсы.

HTTPS, обновления и бэкап двух разных баз

Наружу Langfuse выставляем через Nginx, а не голым портом 3000:

server {
    listen 443 ssl http2;
    server_name langfuse.example.com;

    ssl_certificate     /etc/letsencrypt/live/langfuse.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/langfuse.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

После этого порт web в docker-compose.yml стоит перевести на loopback — 127.0.0.1:3000:3000 вместо 3000:3000 — и закрыть 3000 снаружи через ufw. По умолчанию файл публикует langfuse-web на все интерфейсы намеренно, для тех, кто ставит без обратного прокси вообще; с Nginx в схеме это не нужно.

NEXTAUTH_URL в .env должен буквально совпадать с публичным адресом — протокол, домен, порт. Для входа по email и паролю расхождение не критично, но SSO и OAuth-провайдеры настройки не переживут.

Честная деталь: порт 9090 (MinIO) тоже смотрит наружу без ограничений — браузер забирает вложения из трейсов напрямую из MinIO по presigned-ссылкам, в обход langfuse-web. На одном VPS это рабочий компромисс, но под прод-нагрузку с медиа логичнее вынести хранилище в настоящий S3-бакет за CDN.

Бэкап здесь двусоставный. pg_dump сохраняет организации, проекты, ключи и промпты:

docker compose exec -T postgres pg_dump -U postgres postgres | gzip > /var/backups/langfuse-pg-$(date +%F).sql.gz

Но сами трейсы лежат в ClickHouse, и этот дамп их не заденет — восстановите Postgres и получите рабочую панель с пустой историей. Для ClickHouse нужен отдельный инструмент (clickhouse-backup или BACKUP в SQL); если история трейсов не критична, это осознанный компромисс — но его стоит принять заранее, а не обнаружить после отказа диска.

Обновление — docker compose pull && docker compose up -d, после дампа Postgres. Тег :4 в compose плавающий и сам подтягивает новые релизы; для предсказуемости фиксируйте точный тег — на момент статьи актуальный 4.24.0, свежий смотрите на странице релизов на GitHub.

Какую конфигурацию заказывать в MAATRIX под Langfuse

Проще всего эту связку не собирать руками. Langfuse есть в каталоге apps.maatrix.io: при заказе сервера на Ubuntu или Debian все шесть контейнеров поднимаются сами со сгенерированными секретами, а адрес панели и ключи появляются в личном кабинете, в разделе «Доступ». Всё описанное выше пригодится для своего железа или другого облака — при заказе готового приложения вводить команды руками не нужно.

Минимум — 4 vCPU, 16 ГБ RAM, 100 ГБ NVMe. Ориентир из документации проекта для связки всех шести сервисов на одной машине, не наша прикидка: ClickHouse и Postgres резидентно держат часть данных в памяти, Redis — очередь, плюс два процесса Node.js поверх. Меньше — и на первом же всплеске трафика что-то из шести упадёт по нехватке памяти.

Комфортный вариант — 8 vCPU, 32 ГБ RAM, 200 ГБ NVMe. Запас нужен под рост: объём в ClickHouse растёт с каждой трассой и не убывает сам без настроенного retention, а 100 ГБ на боевом проекте заполняются быстрее, чем кажется на старте. Точнее под свою нагрузку — в отдельном разборе сколько RAM нужно для Langfuse.

Локация — Великобритания, причина не в задержке (SDK шлёт трейсы асинхронно фоном, лишних миллисекунд пользователь приложения не почувствует), а в том, где физически лежат промпты и ответы пользователей. Если LLM-вызовы приложения идут через отдельный шлюз в США, Langfuse от него географически не зависит: сервер с трейсами и сервер с вызовами моделей не обязаны стоять рядом — те же соображения по юрисдикции в статье про VPS в Великобритании для доступа к нейросетям. Для внутреннего RU-проекта без персональных данных из ЕС подойдёт и Россия по 152-ФЗ.

Оплата — картой российского банка, по СБП, криптовалютой или токеном MAAT; для сервера в Лондоне зарубежная карта не нужна.

Развернуть за пару минут

Готовый образ на VPS MAATRIX: NVMe, AMD EPYC, root-доступ. Локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть Langfuse

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →

Частые вопросы

Обязательно ли поднимать все шесть сервисов, чтобы просто попробовать Langfuse?

Для self-host да: ClickHouse и объектное хранилище нужны платформе структурно, а не опционально. Только посмотреть интерфейс можно на бесплатном тарифе cloud.langfuse.com; для полного контроля над данными self-host на VPS остаётся единственным вариантом.

Что будет, если оставить дефолтные CHANGEME-значения из docker-compose.yml?

Порт 3000 смотрит наружу без ограничений по умолчанию, а SALT, ENCRYPTION_KEY и пароли — публично известные строки прямо из репозитория на GitHub. Такой Langfuse находят сканом портов за часы. Меняйте все # CHANGEME в .env до первого docker compose up, не после.

Обязательно ли ставить сервер в Великобритании, если пользователи в России?

Нет: SDK отправляет трейсы асинхронно, в ответ приложения это не попадает. UK оправдан требованиями к месту хранения данных (GDPR), а не задержкой; для внутреннего RU-проекта без персональных данных из ЕС подходит и российская локация по 152-ФЗ.

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.