SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor · 업데이트됨 2026-08-13

Langfuse 셀프 호스팅 가이드: VPS 구축 및 운영 핵심

Langfuse를 자체 VPS에 구축할 때 필요한 리소스 요구사항과 ClickHouse 데이터 보존 설정, TLS 적용 및 안정적인 백업 방법을 다룹니다. v4 버전의 컨테이너 구성과 디스크 용량 문제를 방지하는 실무적인 운영 노하우를 확인하십시오.

AI 에이전트를 추적해야 하는 이유

Langfuse를 직접 호스팅하면 에이전트가 실행 중에 실제로 어떤 작업을 수행했는지 확인할 수 있습니다. Langfuse는 오픈 소스 LLM(거대 언어 모델) 관측성 도구입니다. 모든 프롬프트, 모델 응답, 도구 호출 및 토큰을 기록한 뒤, 이를 열람 가능한 하나의 트레이스로 그룹화합니다. 자체 VPS에서 실행하면 이러한 프롬프트가 사용자가 제어하는 서버 외부로 유출되지 않습니다.

추적을 수행해야 하는 이유는 명확합니다. 볼 수 없는 비용 문제나 품질 문제는 해결할 수 없기 때문입니다. 공급자의 청구서에는 화요일 비용이 월요일보다 4배 더 많이 발생했다는 사실만 적혀 있습니다. 반면 트레이스를 확인하면 어떤 에이전트 실행이 원인인지, 어떤 프롬프트가 40,000 토큰까지 증가했는지, 어떤 재시도 루프가 9번 반복된 후 종료되었는지 알 수 있습니다. 청구서는 결과 수치만 보여주지만, 트레이스는 그 수치를 만들어낸 코드를 보여줍니다.

이 가이드에서는 세 가지 용어를 사용합니다. 트레이스(trace)는 에이전트의 전체 실행 과정을 의미합니다. 관측(observation)은 실행 내부의 한 단계를 의미하며, 일반 코드의 경우 스팬(span), 모델 호출의 경우 생성(generation)으로 구분합니다. 점수(score)는 사람의 검토나 자동 평가기를 통해 트레이스에 부여된 수치입니다. Langfuse는 분산 추적을 위한 벤더 중립 표준인 OpenTelemetry(OTel)를 지원하므로, 이미 구축된 계측 환경을 그대로 연동할 수 있습니다.

Langfuse 셀프 호스팅의 실제 구동 방식

Langfuse v4는 단일 컨테이너가 아닙니다. 두 개의 애플리케이션 컨테이너와 네 개의 스토리지 서비스로 구성되며, 단일 VPS 환경에서는 이 여섯 가지가 모두 해당 서버에서 실행됩니다.

  • langfuse-web은 웹 인터페이스와 수집 API를 제공합니다.
  • langfuse-worker은 백그라운드에서 큐를 처리합니다. 수집된 배치 데이터를 파싱하고 비용을 계산하며, 매일 밤 보존 작업을 수행합니다.
  • Postgres는 사용자, 조직, 프로젝트, API 키, 프롬프트와 같은 트랜잭션 데이터를 저장합니다.
  • ClickHouse는 추적 데이터 자체(관측값 및 점수)를 저장합니다. 분석 쿼리에 최적화된 컬럼형 저장소이므로, 수억 개의 행이 있는 대시보드도 빠르게 응답할 수 있습니다.
  • Redis는 웹과 워커 사이에서 큐와 캐시 역할을 합니다.
  • MinIO는 서버 내에서 S3 호환 객체 스토리지를 제공합니다. 모든 원본 수신 이벤트와 첨부된 미디어를 저장합니다.

Langfuse는 작업을 수행하는 세 가지 구성 요소에 대한 최소 리소스 사양을 공개하고 있습니다.

ChartLangfuse published minimum resources per component
The data behind this chart
[
  {
    "label": "ClickHouse",
    "cpu_cores": 2,
    "memory_gib": 8
  },
  {
    "label": "Langfuse web",
    "cpu_cores": 2,
    "memory_gib": 4
  },
  {
    "label": "Langfuse worker",
    "cpu_cores": 2,
    "memory_gib": 4
  }
]

ClickHouse 단독으로만 8 GiB의 메모리를 요구합니다. 웹 컨테이너와 워커는 각각 4 GiB를 요구합니다. 이는 Langfuse가 산정한 3개 구성 요소의 최소 사양이며, Postgres, Redis, MinIO는 이에 더해 추가적인 메모리가 필요합니다. 프로젝트의 공식 Docker Compose 가이드에서는 4코어 CPU, 16 GiB 메모리, 약 100 GiB의 스토리지를 권장하는데, 이는 여유분을 포함한 수치가 아니라 위 계산에 부합하는 사양입니다.

2 GiB 플랜에서 시도하지 마십시오. ClickHouse는 실행되어 잠시 동안 쓰기 작업을 수행하다가 백그라운드 병합 과정에서 종료됩니다. 병합 작업은 테이블의 상당 부분을 메모리에 로드하기 때문입니다. 이때 docker compose ps은 clickhouse 컨테이너를 restarting 상태로 보고하며, dmesg에는 Out of memory: Killed process 1234 (clickhouse-serv)과 같은 메시지가 기록되고, 모든 Langfuse 대시보드는 500 오류를 반환하게 됩니다. 부하가 적을 때는 ClickHouse가 쿼리를 거부하고 DB::Exception: Memory limit (total) exceeded를 로그에 남깁니다. 8 GiB는 하루에 수천 개의 추적을 보내는 개발자 한 명에게는 운용 가능한 수준입니다. 16 GiB를 기준으로 계획하십시오.

Docker Compose로 Langfuse 배포하기

저장소를 복제합니다. 스택, 연결 설정, 기본 환경 변수는 모두 docker-compose.yml에 포함되어 있습니다.

git clone https://github.com/langfuse/langfuse.git
cd langfuse

해당 파일에서 변경해야 하는 모든 값은 # CHANGEME로 표시되어 있습니다. 먼저 세 가지 애플리케이션 보안 키를 생성합니다.

openssl rand -base64 32   # NEXTAUTH_SECRET
openssl rand -base64 32   # SALT
openssl rand -hex 32      # ENCRYPTION_KEY

ENCRYPTION_KEY는 64자 16진수로 작성된 256비트 값이어야 하며, openssl rand -hex 32 명령어가 정확히 이 형식으로 출력합니다. 이 값은 인스턴스에 저장된 LLM 제공자 키를 포함하여 저장된 민감한 데이터를 암호화합니다. 데이터가 생성된 후 이 값을 변경하면 기존 데이터를 복호화할 수 없으므로, 최초 부팅 시점부터 영구적인 값으로 취급해야 합니다. SALT은 Langfuse API 키를 해싱하는 데 사용되므로, 이 값을 변경하면 에이전트가 이미 사용 중인 모든 키가 무효화됩니다.

그다음 POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH, MINIO_ROOT_PASSWORD을 설정합니다. MinIO 비밀번호는 MINIO_ROOT_PASSWORD, LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_MEDIA_UPLOAD_SECRET_ACCESS_KEY, LANGFUSE_S3_BATCH_EXPORT_SECRET_ACCESS_KEY와 같이 네 곳에 입력해야 합니다. 하나라도 누락되면 MinIO는 SignatureDoesNotMatch 오류와 함께 클라이언트 연결을 거부하며, 웹 인터페이스는 정상으로 보이지만 워커 로그에는 오류가 기록됩니다. 이 값들을 추적되는 compose 파일에 직접 넣지 않고 env 파일로 관리하는 방식은 Docker Compose env 파일 및 보안 키에서 다룹니다.

시작 전 이미지 태그 고정하기

제공되는 파일은 langfuse/langfuse:4langfuse/langfuse-worker:4 태그를 사용합니다. 이 태그들은 계속 변경됩니다. Langfuse는 시작 시 Postgres 및 ClickHouse 마이그레이션을 자동으로 수행하므로, 몇 달 뒤 일상적인 docker compose pull를 실행하면 당일 백업하지 않은 데이터베이스에서 예기치 않은 스키마 마이그레이션이 발생할 수 있습니다. 두 태그를 특정 릴리스 버전으로 docker-compose.override.yml에 고정하십시오. Compose는 이를 기존 파일 위에 병합하므로 나중에 git pull을 실행해도 사용자가 수정한 내용이 덮어씌워지지 않습니다.

services:
  langfuse-web:
    image: docker.io/langfuse/langfuse:4.3.1
  langfuse-worker:
    image: docker.io/langfuse/langfuse-worker:4.3.1

2026년 8월 기준 4.3 버전의 최신 릴리스는 4.3.1입니다(이후 4.4.0이 출시되었습니다). 프로젝트의 GitHub 릴리스 페이지를 확인하여 배포 당일 최신 버전을 고정하고, 이후 의도적으로 버전을 업데이트하십시오. 제공된 파일의 스토리지 이미지들은 이미 메이저 버전인 postgres:17, clickhouse-server:25.12, redis:7로 고정되어 있으며, 이들 역시 동일하게 관리해야 합니다.

서비스를 시작합니다.

docker compose up -d
docker compose ps
docker compose logs -f langfuse-worker

최초 부팅 시 마이그레이션이 실행되므로 응답이 올 때까지 1~2분 정도 기다려야 합니다. docker compose ps를 실행하면 6개의 서비스가 running 상태로 표시되어야 합니다. 워커가 반복적으로 재시작된다면 로그에서 원인을 확인하십시오. CLICKHOUSE_MIGRATION_URL은 HTTP 포트 8123이 아닌 ClickHouse 네이티브 프로토콜 포트 9000을 사용합니다. 8123으로 설정하면 웹 컨테이너는 정상으로 보여도 워커에서 연결 오류가 발생합니다.

서버 내부에서 상태를 확인합니다.

curl -s "http://localhost:3000/api/public/health?failIfDatabaseUnavailable=true"
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:3000/api/public/ready

단순한 /api/public/health 호출은 API 프로세스가 살아있는지만 확인합니다. 이 방식은 데이터베이스 연결을 확인하지 않으므로 Postgres에 일시적인 문제가 있어도 서비스가 정상인 것처럼 보일 수 있습니다. 모니터링 도구에는 failIfDatabaseUnavailable=true 형식을 사용해야 하며, 데이터베이스에 연결할 수 없으면 503을 반환합니다. /api/public/ready은 마이그레이션이 완료되고 컨테이너가 트래픽을 수용할 준비가 되면 200을 반환합니다. 두 방식 모두 일반적인 HTTP 확인이므로 Uptime Kuma 상태 페이지를 통해 모니터링하면 에이전트가 문제를 감지하기 전에 스택 중단 여부를 먼저 파악할 수 있습니다.

TLS를 앞단에 배치하고 추가 포트 닫기

제공되는 compose 파일은 웹 컨테이너를 위해 3000:3000을, MinIO를 위해 9090:9000를 공개합니다. 두 포트 모두 모든 인터페이스에 바인딩됩니다. 공인 IP 환경에서 포트 3000을 스캔하는 누구든 가입 페이지에 접근할 수 있으며, 9090을 스캔하는 누구든 원본 프롬프트가 저장된 버킷과 통신할 수 있게 됩니다.

방화벽 규칙만으로는 이 포트들을 닫을 수 없습니다. Docker는 자체적으로 nat 테이블에 DNAT 규칙을 작성하며, 이 규칙은 ufw의 필터 규칙이 패킷을 확인하기 전에 먼저 평가되므로 ufw deny 3000은 공개된 포트를 그대로 열어둡니다. 이 문제는 매우 흔하여 별도의 가이드가 존재합니다: Docker 공개 포트가 ufw를 우회하는 이유. 대신 override 파일에서 루프백(loopback) 주소에 바인딩하십시오.

services:
  langfuse-web:
    ports:
      - "127.0.0.1:3000:3000"
    environment:
      NEXTAUTH_URL: https://langfuse.example.com
  minio:
    ports:
      - "127.0.0.1:9090:9000"
      - "127.0.0.1:9091:9001"

NEXTAUTH_URL는 스킴(scheme)을 포함한 정확한 공인 주소여야 합니다. 로그인 과정에서 해당 값을 사용하여 콜백 URL을 생성하기 때문입니다. HTTPS 프록시 뒤에서 http://localhost:3000로 그대로 두면, 로그인 왕복 과정에서 브라우저가 도달할 수 없는 곳으로 리다이렉트됩니다.

이제 리버스 프록시를 127.0.0.1:3000으로 지정하고 인증서를 관리하게 하십시오. 동일한 Compose 프로젝트 내의 Traefik을 사용하는 것이 일반적이며, 라우팅 레이블은 하나의 Traefik 리버스 프록시 뒤에서 여러 앱 실행하기에서 다루는 내용을 따릅니다. 서버에 Langfuse만 운영한다면 Caddy로도 두 줄의 설정만으로 동일한 작업을 수행할 수 있습니다. curl -sI https://langfuse.example.com/api/public/ready로 확인한 뒤, 다른 기기에서 curl http://YOUR_IP:3000에 접속했을 때 타임아웃이 발생하는지 확인하십시오.

MinIO 사용 시 주의할 점이 하나 있습니다. Langfuse는 S3 엔드포인트를 가리키는 사전 서명된(presigned) URL을 통해 첨부된 미디어를 브라우저로 제공합니다. 따라서 이미지나 오디오가 포함된 멀티모달 트레이스를 사용하는 경우, 루프백 전용으로 설정된 MinIO에서는 해당 첨부 파일이 로드되지 않습니다. 사전 서명된 URL에 기록되는 엔드포인트는 실제 공개된 주소와 일치해야 하므로, 프록시를 설정하기 전에 블롭 스토리지 설정 페이지를 먼저 읽어보시기 바랍니다. 일반 텍스트 트레이스는 영향을 받지 않습니다.

첫 방문 시 계정을 생성한 후, 해당 인스턴스를 본인만 사용하도록 제한하십시오. LANGFUSE_ALLOWED_ORGANIZATION_CREATORS를 본인의 이메일 주소로 설정하여, 페이지에 접속한 낯선 사람이 서버에 조직을 생성하지 못하도록 하십시오. 이미 Authentik을 자체 ID 공급자로 운영 중이라면, Langfuse는 표준 OIDC 연결을 지원하므로 이 서버에만 존재하는 비밀번호 목록에 의존하지 않고 다른 앱들과 통합하여 계정을 관리할 수 있습니다.

첫 번째 트레이스 전송하기

웹 인터페이스에서 프로젝트를 생성하고 프로젝트 설정에서 공개 키와 비밀 키를 복사합니다. Python SDK는 세 가지 환경 변수를 읽습니다.

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

LANGFUSE_BASE_URL은 2026년 3월에 릴리스된 SDK v4의 변수명입니다. 이전 코드나 가이드는 LANGFUSE_HOST을 사용합니다. 트레이스가 서버가 아닌 Langfuse Cloud로 전송된다면, 기본 URL이 호스팅된 인스턴스를 가리키기 때문에 설정되지 않은 base URL이 원인입니다.

pip install langfuse opentelemetry-instrumentation-anthropic anthropic
import os
from anthropic import Anthropic
from langfuse import get_client, observe
from opentelemetry.instrumentation.anthropic import AnthropicInstrumentor

AnthropicInstrumentor().instrument()
langfuse = get_client()
client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

@observe(as_type="tool")
def lookup_order(order_id: str) -> str:
    return f"order {order_id}: shipped"

@observe()
def handle_request(question: str) -> str:
    context = lookup_order("A-1042")
    message = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=512,
        messages=[{"role": "user", "content": f"{context}\n\n{question}"}],
    )
    return message.content[0].text

if __name__ == "__main__":
    assert langfuse.auth_check()
    print(handle_request("Where is my order?"))
    langfuse.flush()

@observe 데코레이터는 함수 주변에 관찰(observation)을 생성하여 인자와 반환값을 캡처하고, 이미 활성화된 관찰 아래에 중첩합니다. AnthropicInstrumentor은 Anthropic 클라이언트를 위한 OpenTelemetry 계측 도구이며, 호출 지점의 변경 없이 각 messages.create 호출을 모델명, 토큰 사용량, 지연 시간을 포함한 생성(generation)으로 변환합니다.

두 가지 호출을 통해 확인을 수행할 수 있습니다. langfuse.auth_check()는 잘못된 키나 잘못된 base URL이 입력된 경우 False를 반환하며, 이는 대시보드가 비어 있는 이유를 고민하는 것보다 빠릅니다. langfuse.flush()은 큐에 담긴 스팬(span)이 전송될 때까지 차단합니다. SDK는 백그라운드에서 배치를 처리하므로, 즉시 종료되는 스크립트는 전송되지 않은 배치를 함께 소멸시키기 때문에 단기 실행 프로세스에서는 이 호출이 필요합니다.

ClickHouse의 디스크 사용량이 계속 증가하는 이유는 무엇입니까?

트레이스(trace) 데이터는 개인이 직접 호스팅하는 데이터 중 가장 빠르게 증가하는 유형입니다. 에이전트가 실행될 때마다 단계별로 한 행씩 기록되며, 입력과 출력 내용이 전체 저장되므로 긴 프롬프트를 사용하는 에이전트는 감시 대상 애플리케이션보다 훨씬 많은 바이트를 매일 생성합니다. 방치할 경우 ClickHouse는 디스크를 가득 채우게 되며, 디스크가 꽉 차면 데이터 수집 속도가 느려지는 것이 아니라 수집 자체가 중단됩니다.

여기에는 두 가지 서로 다른 증가 요인이 있으며, 각각 별도의 해결책이 필요합니다.

첫 번째는 사용자의 트레이스 데이터이며, 해결책은 보존 기간(retention) 설정입니다. 웹 인터페이스에서 프로젝트 설정을 열고 데이터 보존 기간을 일 단위로 설정하십시오. Langfuse는 최소 3일 이상의 보존 기간을 지원합니다. 매일 밤 실행되는 작업이 설정된 기간보다 오래된 트레이스, 관찰(observation), 점수(score) 및 미디어 자산을 선택하여 ClickHouse와 블롭(blob) 저장소에서 삭제합니다. 이 작업에는 버킷에 대한 DeleteObject 권한이 필요하며, 기본 compose 파일에 포함된 MinIO 루트 자격 증명은 이미 이 권한을 가지고 있습니다. 삭제는 영구적이므로 장기 기록이 필요하다면 먼저 블롭 저장소 내보내기(export)를 구성하십시오. Langfuse의 테이블에 직접 TTL 절을 작성하지 마십시오. 보존 작업이 ClickHouse와 버킷의 동기화를 유지하며, 수동으로 TTL을 설정하면 한쪽 데이터만 삭제될 수 있습니다.

실제 사용량에 맞춰 기간을 선택하십시오. 비용 및 품질 검토는 수개월 전 데이터가 아닌 며칠 전 데이터를 대상으로 수행됩니다. 소규모 팀이라면 30일로 시작하는 것이 적절하며, 문제가 발생했을 때만 트레이스를 확인한다면 14일로도 충분합니다.

두 번째는 ClickHouse 자체의 시스템 로그 테이블이며, 보존 기간을 설정한 후에도 디스크 사용량이 계속 증가하여 사용자들을 당황하게 만듭니다. ClickHouse는 진단을 위해 trace_log, text_log, opentelemetry_span_log, metric_logasynchronous_metric_log를 기록하는데, 이들은 기본적으로 TTL이 설정되어 있지 않으며 Langfuse는 이를 읽지 않습니다. 먼저 디스크 공간을 실제로 점유하고 있는 항목을 확인하십시오.

SELECT table, formatReadableSize(size) AS size, rows FROM (
    SELECT table, database, sum(bytes) AS size, sum(rows) AS rows
    FROM system.parts
    WHERE active
    GROUP BY table, database
    ORDER BY size DESC
)

docker compose exec clickhouse clickhouse-client --password "$CLICKHOUSE_PASSWORD" 명령으로 실행하십시오. 시스템 테이블이 상위권을 차지하고 있다면 설정 오버레이를 사용하여 해당 기능을 끄십시오. ClickHouse는 시작 시 /etc/clickhouse-server/config.d/에 있는 모든 파일을 메인 설정 위에 병합합니다.

<clickhouse>
    <trace_log remove="1"/>
    <text_log remove="1"/>
    <opentelemetry_span_log remove="1"/>
    <asynchronous_metric_log remove="1"/>
    <metric_log remove="1"/>
</clickhouse>

해당 파일을 마운트하고 ClickHouse를 재시작하십시오.

services:
  clickhouse:
    volumes:
      - ./clickhouse-config.d/system-logs.xml:/etc/clickhouse-server/config.d/system-logs.xml:ro

이 작업으로 새로운 기록이 중단됩니다. 이미 디스크에 있는 행은 그대로 남아 있으므로 DROP TABLE IF EXISTS system.trace_log 명령을 사용하여 공간을 명시적으로 회수하십시오. 제거한 각 테이블에 대해서도 동일하게 수행하십시오. 진단 데이터를 유지하고 싶다면 remove="1" 대신 각 테이블에 공격적인 TTL을 설정하는 대안이 있으며, 이는 Langfuse 확장성 문서에 자세히 설명되어 있습니다.

한 가지 더 알아두어야 할 테이블이 있습니다. blob_storage_file_log은 버킷에 업로드된 이벤트 파일을 추적합니다. 버킷에 수명 주기 정책(lifecycle policy)을 설정했다면, 두 데이터가 어긋나지 않도록 해당 테이블에도 일치하는 TTL을 설정하십시오.

ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;

데이터 디스크에 일반적인 df -h 알림을 설정하십시오. 트레이스는 일정하게 증가하지 않습니다. 새로운 에이전트를 배포하는 날 급격히 증가하며, 그 첫 번째 징후가 데이터 수집 실패가 되어서는 안 됩니다.

Postgres 및 ClickHouse 백업

Langfuse 백업은 세 부분으로 구성됩니다. Postgres는 사용자, 조직, 프로젝트 및 API 키를 보관합니다. ClickHouse는 트레이스를 보관합니다. MinIO는 원시 이벤트를 보관합니다. Postgres만 복원하면 로그인은 가능하지만 기록이 없습니다. ClickHouse만 복원하면 기록은 있지만 아무도 로그인하여 볼 수 없습니다.

Postgres는 일반적인 pg_dump를 사용하며, 이는 Langfuse 백업 문서에서 권장하는 방식입니다.

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

ClickHouse는 더 주의가 필요합니다. 병합이 진행 중일 때 라이브 데이터 디렉터리를 복사하면 일관된 백업이 되지 않기 때문입니다. 단일 서버에서 사용하는 간단한 방법은 컨테이너를 중지하고 볼륨을 아카이브하는 것입니다.

docker compose stop clickhouse
docker volume ls | grep clickhouse
docker run --rm -v langfuse_langfuse_clickhouse_data:/data -v "$PWD":/backup alpine \
  tar czf /backup/langfuse-ch-$(date +%F).tar.gz -C /data .
docker compose start clickhouse

YAML에 작성된 이름이 아니라 docker volume ls이 출력하는 볼륨 이름을 사용하십시오. 파일에는 langfuse_clickhouse_data로 선언되어 있지만, Compose는 프로젝트 이름을 접두사로 붙입니다. 따라서 langfuse라는 디렉터리에서 복제하면 langfuse_langfuse_clickhouse_data이 생성됩니다. 이를 잘못 입력하면 docker run는 경고 없이 새로운 빈 볼륨을 생성하며, 아카이브에는 아무것도 담기지 않게 됩니다.

웹 컨테이너는 워커가 처리하기 전에 모든 수신 이벤트를 버킷에 기록하므로, ClickHouse를 잠시 중지하더라도 워커가 나중에 재시도하게 됩니다. 트래픽이 적은 시간에 수행하고 중지 시간을 짧게 유지하십시오. 사용량이 많은 인스턴스의 경우, ClickHouse의 BACKUP DATABASE default TO S3(...) 문을 사용하면 서버를 중지하지 않고도 일관된 백업을 생성할 수 있습니다. MinIO는 세 번째 요소이며, mc mirror 또는 외부 버킷으로의 MinIO 복제를 통해 백업할 수 있습니다. 어떤 방식을 사용하든 데이터를 서버 외부로 반출해야 하며, 이것이 바로 VPS의 암호화된 restic 백업이 필요한 이유입니다.

Redis는 백업이 필요하지 않습니다. 큐와 캐시를 보관하므로, 유실되더라도 처리 중인 이벤트만 손실될 뿐 과거 데이터는 안전합니다.

일관성 문제는 실재하며 명확히 언급할 가치가 있습니다. Postgres와 ClickHouse는 서로 다른 시점에 덤프되므로, 복원 후 프로젝트 행은 존재하지만 트레이스가 없거나, 존재하지 않는 프로젝트에 속한 트레이스가 남을 수 있습니다. Langfuse는 이를 허용하지만, 두 덤프를 최대한 가까운 시점에, 트래픽이 낮은 시간대에 수행하십시오. 이벤트 버킷은 진정한 안전망 역할을 합니다. Langfuse는 처리하기 전에 모든 수신 이벤트를 해당 버킷에 영구 저장하기 때문입니다.

최소 한 번은 테스트용 스택에 복원해 보십시오. 이것이 장애 발생 시점이 아닌 지금, 잘못된 볼륨 이름을 찾아내는 방법입니다.

가장 먼저 확인해야 할 사항

첫 주에는 다음 네 가지를 우선적으로 확인해야 합니다.

  • 트레이스당 비용. Langfuse는 모델명과 토큰 사용량을 기반으로 비용을 계산합니다. 따라서 비용순으로 트레이스를 정렬하고 가장 비용이 많이 발생한 트레이스를 처음부터 끝까지 검토하십시오. 원인은 보통 비대해진 프롬프트입니다. 전체 문서를 컨텍스트에 붙여넣었거나, 아무도 정리하지 않은 대화 기록이 쌓여 있는 경우가 많습니다. 이를 확인하면 AI 에이전트 비용 제어는 추측이 아닌 엔지니어링 작업이 됩니다.
  • 입력 및 출력별 토큰 사용량 분할. 입력 토큰은 양이 많고 저렴하며, 출력 토큰은 양이 적고 비쌉니다. 캐시된 입력은 더 저렴합니다. 동일한 계산 방식이 Claude Code 토큰 사용량 산정 방식에 설명되어 있으며, 이는 직접 작성하는 모든 에이전트에도 적용됩니다.
  • 지연 시간 백분위수. 중앙값은 문제를 숨깁니다. p95와 p99에서 타임아웃이 발생하며, 에이전트 루프 내부에서는 p95의 느린 도구 호출이 반복 횟수만큼 곱해져 성능을 저하시킵니다.
  • 실패한 도구 호출. 레벨 ERROR로 관측값을 필터링하십시오. 5%의 확률로 실패하는 도구는 전체 성공률에서는 보이지 않지만, 트레이스에서는 명확하게 드러납니다. 트레이스를 통해 모델이 재시도하고 이를 우회하기 위해 토큰을 낭비하는 과정을 확인할 수 있습니다.

보존 기간을 설정하고 매주 배포하는 날에 확인할 대시보드를 선택하십시오. 아무도 열어보지 않는 관측 도구는 디스크만 채우는 데이터베이스일 뿐입니다.

FAQ

자체 호스팅 Langfuse는 메모리가 얼마나 필요한가?

CPU 4코어와 16 GiB 메모리를 확보하십시오. 이는 단일 가상 머신에서 Langfuse Docker Compose 가이드가 권장하는 사양이며, 약 100 GiB의 저장 공간이 추가로 필요합니다. 공개된 구성 요소별 최소 사양은 ClickHouse가 8 GiB, 웹 및 워커 컨테이너가 각각 4 GiB이며, Postgres, Redis, MinIO는 이와 별도로 메모리가 필요합니다. 8 GiB 환경에서는 개발자용 인스턴스 하나를 실행할 수 있습니다. 2 GiB 환경에서는 실행이 불가능합니다. ClickHouse가 백그라운드 병합 과정에서 커널에 의해 강제 종료되며, dmesgOut of memory: Killed process를 표시합니다.

데이터 보존 기간을 설정했는데도 왜 ClickHouse 디스크가 계속 가득 차는가?

보존 설정은 Langfuse의 자체 데이터에만 적용됩니다. ClickHouse는 이와 별도로 진단 테이블인 trace_log, text_log, opentelemetry_span_log, metric_log, asynchronous_metric_log에 데이터를 기록하며, 이들에는 TTL이 설정되어 있지 않습니다. system.parts 쿼리를 테이블별로 그룹화하여 가장 큰 테이블을 확인한 다음, /etc/clickhouse-server/config.d/ 하위 파일에 remove="1" 항목을 추가하여 사용하지 않는 테이블을 비활성화하십시오. 이후 ClickHouse를 재시작하고 기존 테이블을 삭제하여 점유된 공간을 확보하십시오.

Langfuse의 최소 데이터 보존 기간은 얼마인가?

3일입니다. 보존 기간은 프로젝트 설정 또는 프로젝트 API를 통해 프로젝트별로 지정할 수 있으며, 매일 밤 실행되는 작업이 설정된 기간보다 오래된 추적(trace), 관찰(observation), 점수(score) 및 미디어 자산을 ClickHouse와 blob 저장소에서 삭제합니다. 삭제된 데이터는 복구할 수 없으므로, 해당 기간 이후의 기록이 필요하다면 먼저 blob 저장소 내보내기를 구성하십시오.

Postgres와 ClickHouse를 모두 백업해야 하는가?

그렇습니다. 두 데이터베이스가 저장하는 정보가 서로 다르기 때문입니다. Postgres는 사용자, 조직, 프로젝트, API 키를 저장하며, ClickHouse는 추적 데이터 자체를 저장합니다. Postgres만 복구하면 로그인은 가능하지만 데이터가 없는 빈 인스턴스가 됩니다. MinIO 버킷도 함께 백업하십시오. 이곳에는 Langfuse가 수신 즉시 영구 저장하는 원본 이벤트가 보관되며, 이는 해당 스택에서 원천 데이터에 가장 가까운 정보입니다.

기존 OpenTelemetry 설정을 자체 호스팅 Langfuse에 연결할 수 있는가?

그렇습니다. Langfuse v4와 v4 SDK는 OpenTelemetry를 기반으로 구축되었으며, Anthropic 및 OpenAI OTel 계측은 이를 직접 내보냅니다. Python에서는 pip install langfuse opentelemetry-instrumentation-anthropic을 실행하고 시작 시 AnthropicInstrumentor().instrument()를 한 번 호출한 뒤, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY, LANGFUSE_BASE_URL를 자신의 호스트로 설정하십시오. 대시보드에서 데이터가 보이지 않는 문제를 조사하기 전에 langfuse.auth_check()으로 연결을 확인하십시오.