Skip to content

필사 모드: Langfuse 자체 호스팅 — 배포 경로, 시크릿, 그리고 첫 기동에서 걸리는 것들

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며 — 무엇을 띄우는지 알고 시작하기

3편에서 구성 요소를 봤습니다. 웹과 워커 컨테이너, 그리고 Postgres, ClickHouse, Redis, 오브젝트 스토리지입니다. 이번 글은 그것들을 실제로 세우는 쪽입니다.

자체 호스팅에서 시간을 가장 많이 잡아먹는 것은 배포 도구가 아닙니다. 값을 잘못 넣은 환경 변수 하나입니다. 그리고 잘못된 값은 대개 조용히 실패합니다. 컨테이너는 뜨고, 로그인도 되는데, 트레이스만 안 들어옵니다.

구성과 설정 이름은 2026-08-15에 공식 문서에서 확인했습니다. Langfuse는 버전에 따라 아키텍처가 달라지므로 사용 중인 버전의 문서를 다시 확인하세요. 아래 이름과 기본값은 v4 문서 기준입니다. 문서에서 확인하지 못한 값은 이 글에 적지 않았습니다.

가장 빠른 경로 — docker compose

docker compose 문서가 안내하는 절차는 저장소를 받아 compose를 올리는 것입니다.

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

# 시크릿을 먼저 바꾼 뒤에 올린다
docker compose up -d
docker compose ps

저장소 최상단의 compose 파일을 2026-08-15에 확인한 기준으로, 정의된 서비스와 이미지는 다음과 같습니다.

서비스이미지노출
langfuse-webdocker.io/langfuse/langfuse:43000번을 외부로
langfuse-workerdocker.io/langfuse/langfuse-worker:43030번을 루프백에만
postgresdocker.io/postgres (기본 태그 17)루프백에만
clickhousedocker.io/clickhouse/clickhouse-server:25.12루프백에만
redisdocker.io/redis:7루프백에만
miniocgr.dev/chainguard/minio9090번을 외부로

두 Langfuse 서비스는 네 저장소 모두에 헬스 체크 기반 의존성을 걸고 있습니다. 그래서 저장소가 준비되기 전에는 기동하지 않습니다. 문서는 인스턴스에 보안 그룹이나 방화벽을 두어 3000번과 9090번으로만 들어오게 제한하라고 권고합니다.

compose 파일 안에서 바꿔야 하는 줄에는 # CHANGEME 주석이 붙어 있습니다. 이 주석을 전부 찾아 처리하기 전에는 프로덕션으로 올리면 안 됩니다.

반드시 직접 만들어 넣는 값

설정 문서가 필수로 표시하는 보안 관련 변수는 네 개입니다.

변수문서가 설명하는 용도
NEXTAUTH_URLLangfuse 웹 배포의 URL
NEXTAUTH_SECRET로그인 세션 쿠키 검증에 사용
SALT해시된 API 키에 소금을 치는 데 사용
ENCRYPTION_KEY민감한 데이터 암호화에 사용

문서는 NEXTAUTH_SECRETSALT에 256비트 이상의 엔트로피를, ENCRYPTION_KEY에는 16진수 형식의 256비트 값을 요구합니다.

# 예시: 요구되는 형식에 맞는 값을 만든다
openssl rand -base64 32   # NEXTAUTH_SECRET
openssl rand -base64 32   # SALT
openssl rand -hex 32      # ENCRYPTION_KEY (16진수 256비트)

SALTENCRYPTION_KEY는 나중에 바꾸면 기존 데이터를 읽지 못하게 됩니다. 배포 첫날에 정하고 시크릿 관리 시스템에 넣어 두세요. NEXTAUTH_URL은 실제 접속 주소와 정확히 같아야 합니다. 리버스 프록시 뒤에서 이 값이 내부 주소로 남아 있으면 로그인 리다이렉트가 깨집니다.

저장소별 연결 설정

Postgres 쪽에서 문서가 정의하는 변수는 네 개입니다.

  • DATABASE_URL — Postgres 연결 문자열입니다. 필수입니다.
  • DIRECT_URL — 마이그레이션에 쓰는 연결 문자열입니다. 기본값은 DATABASE_URL이며, 마이그레이션 전용 계정이나 풀러를 우회한 직결이 필요할 때 따로 줍니다.
  • SHADOW_DATABASE_URL — 데이터베이스 사용자에게 데이터베이스 생성 권한이 없을 때 필요합니다.
  • LANGFUSE_AUTO_POSTGRES_MIGRATION_DISABLED — 기본값 false이며, 기동 시 자동 마이그레이션을 끕니다.

ClickHouse 쪽은 연결 문자열이 두 개라는 점이 처음 보면 헷갈립니다. 프로토콜이 다르기 때문입니다.

# 예시: 프로토콜이 서로 다른 두 엔드포인트
CLICKHOUSE_MIGRATION_URL="clickhouse://clickhouse-host:9000"   # TCP, 9000 또는 9440
CLICKHOUSE_URL="http://clickhouse-host:8123"                   # HTTP(S), 8123 또는 8443
CLICKHOUSE_USER="langfuse"
CLICKHOUSE_PASSWORD="changeme"
CLICKHOUSE_DB="langfuse"
CLICKHOUSE_CLUSTER_ENABLED="false"

ClickHouse 문서가 밝히는 패턴이 이것입니다. 마이그레이션은 TCP 프로토콜로, 일반 질의는 HTTP로 나갑니다. CLICKHOUSE_DB의 기본값은 default이고, CLICKHOUSE_CLUSTER_ENABLED의 기본값은 true입니다. 단일 컨테이너로 띄웠다면 이 값을 false로 내려야 합니다. 클러스터 이름은 CLICKHOUSE_CLUSTER_NAME으로 바꾸며 기본값은 default입니다. SSL이 필요하면 CLICKHOUSE_MIGRATION_SSL을 켭니다.

사용자 권한은 3편에서 본 그대로입니다. INSERT, SELECT, ALTER UPDATE, ALTER DELETE, ALTER DROP INDEX, CREATE, DROP TABLE이 필요합니다. 이 중 하나라도 빠지면 마이그레이션 단계에서 멈춥니다.

Redis는 REDIS_CONNECTION_STRING 하나로 지정하거나 REDIS_HOST, REDIS_PORT, REDIS_AUTH로 나눠 줍니다. 클러스터와 센티널 모드를 쓴다면 각각 REDIS_CLUSTER_ENABLEDREDIS_SENTINEL_ENABLED 계열 변수가 따로 있습니다. 그리고 3편에서 강조한 maxmemory-policynoeviction으로 두는 설정을 잊지 마세요.

오브젝트 스토리지 설정

오브젝트 스토리지 문서에서 필수로 표시된 것은 이벤트 업로드 버킷입니다. 미디어 업로드 버킷도 설정 문서에서는 필수로 표시됩니다.

# 예시: MinIO 를 쓰는 경우
LANGFUSE_S3_EVENT_UPLOAD_BUCKET="langfuse"
LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT="http://minio:9000"
LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID="minio"
LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY="changeme"
LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE="true"
LANGFUSE_S3_EVENT_UPLOAD_PREFIX="events/"

LANGFUSE_S3_MEDIA_UPLOAD_BUCKET="langfuse"
LANGFUSE_S3_MEDIA_UPLOAD_ENDPOINT="http://minio:9000"
LANGFUSE_S3_MEDIA_UPLOAD_FORCE_PATH_STYLE="true"

두 가지를 기억하면 됩니다. 접두사를 줄 때는 반드시 슬래시로 끝나야 합니다. 그리고 MinIO에서는 경로 방식 강제 옵션이 필요하다고 문서가 명시합니다. 이 옵션이 없으면 버킷 이름이 호스트명으로 해석되면서 이름 해석에 실패합니다.

배치 내보내기는 기본값이 꺼져 있습니다. LANGFUSE_S3_BATCH_EXPORT_ENABLED를 켜면 별도의 버킷 설정이 필요해집니다. AWS S3라면 필요한 최소 권한은 버킷과 객체 양쪽에 대한 s3:PutObject, s3:ListBucket, s3:GetObject입니다.

쿠버네티스 경로 — 헬름 차트

헬름 문서가 안내하는 차트 저장소와 설치 명령은 다음과 같습니다.

helm repo add langfuse https://langfuse.github.io/langfuse-k8s
helm repo update
helm install langfuse langfuse/langfuse -n langfuse --create-namespace

기본 설치는 애플리케이션 컨테이너와 데이터 저장소를 함께 올립니다. 이미 운영 중인 Postgres, ClickHouse, Redis를 가리키게 바꿀 수도 있습니다. 차트 저장소의 README가 밝히는 값 구조는 최상위 키가 langfuse, postgresql, clickhouse, redis, 그리고 s3 또는 minio로 나뉘는 형태입니다.

# 예시: 시크릿을 값 파일에 직접 쓰지 않는 형태
langfuse:
  salt:
    secretKeyRef:
      name: langfuse-secrets
      key: salt
  nextauth:
    secret:
      secretKeyRef:
        name: langfuse-secrets
        key: nextauth-secret
  encryptionKey:
    secretKeyRef:
      name: langfuse-secrets
      key: encryption-key

postgresql:
  auth:
    username: langfuse
    existingSecret: langfuse-postgres

clickhouse:
  auth:
    existingSecret: langfuse-clickhouse

redis:
  auth:
    existingSecret: langfuse-redis

s3:
  storageProvider: s3

값의 정확한 중첩 형태는 차트 버전에 따라 달라지므로, 실제 키 이름과 기본값은 사용 중인 버전의 문서와 차트 README에서 확인하세요. README가 명시하는 원칙은 두 가지입니다. 비밀번호는 값으로 직접 쓰거나 existingSecretexistingSecretKey로 기존 시크릿을 가리킬 수 있고, 외부 데이터 저장소를 쓰면 차트 릴리스와 저장소의 수명 주기를 분리할 수 있습니다.

주의할 점이 하나 있습니다. 릴리스 이름을 langfuse가 아닌 다른 이름으로 설치하면 Redis 호스트명을 그에 맞게 조정해야 한다고 문서가 밝힙니다. 헬름의 이름 조합 규칙 때문에 생기는 문제입니다.

첫 기동에서 확인할 것

헬름 문서는 배포가 최대 5분까지 걸릴 수 있고, 그 사이 langfuse-web과 langfuse-worker 컨테이너가 데이터베이스 준비 과정에서 재시작한다고 밝힙니다. 즉 초기에 보이는 재시작은 정상 동작입니다. 5분이 지나도 반복된다면 그때부터 진짜 문제입니다.

# 컨테이너 상태와 로그
docker compose ps
docker compose logs -f langfuse-web
docker compose logs -f langfuse-worker

# 웹이 응답하는지 확인
curl -sS -o /dev/null -w "%{http_code}\n" http://localhost:3000

확인 순서는 이렇게 잡으면 좋습니다.

  1. 네 저장소가 모두 healthy 상태인지 봅니다. 여기서 막히면 애플리케이션 로그를 볼 필요가 없습니다.
  2. 웹 로그에서 마이그레이션이 끝났는지 확인합니다. Postgres와 ClickHouse 양쪽입니다.
  3. 웹에 접속해 계정을 만들고 프로젝트를 만듭니다. 여기까지는 Postgres만으로 됩니다.
  4. SDK로 트레이스를 하나 보냅니다. 화면에 뜨면 ClickHouse, Redis, 오브젝트 스토리지가 모두 살아 있다는 뜻입니다.

4번이 3편에서 본 수집 경로를 통째로 검증합니다. 그래서 첫 기동 확인은 여기까지 해야 끝입니다.

흔한 실패

문서에 근거가 있는 실패 유형을 모으면 다음과 같습니다.

증상원인확인할 것
질의가 빈 결과를 반환인프라 구성 요소가 UTC가 아님모든 저장소 컨테이너의 시간대
마이그레이션 단계에서 정지ClickHouse 사용자 권한 부족3편의 GRANT 목록
마이그레이션이 CREATE DATABASE 실패Postgres 사용자 권한 부족SHADOW_DATABASE_URL
큐 이벤트가 사라짐maxmemory-policy가 noeviction이 아님Redis 설정
버킷 접근 실패경로 방식 옵션 누락LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE
컨테이너가 메모리로 죽음Node 힙 상한 미설정NODE_OPTIONS
로그인 리다이렉트가 깨짐외부 주소와 불일치NEXTAUTH_URL

마지막에서 두 번째 항목은 컨테이너 문서가 명시하는 사항입니다. 컨테이너에 할당한 메모리가 Node의 기본 상한인 약 1.7GiB를 넘을 때, NODE_OPTIONS로 힙 크기를 명시하지 않으면 문제가 생깁니다. 두 컨테이너 모두에 설정해야 합니다.

기동 문제를 추적할 때는 로그 설정도 도움이 됩니다. LANGFUSE_LOG_LEVEL의 기본값은 info이고 trace부터 fatal까지 조절할 수 있습니다. LANGFUSE_LOG_FORMAT은 기본 text이며 json으로 바꾸면 로그 수집 파이프라인에 넣기 쉬워집니다.

프로덕션으로 넘어가기 전에

컨테이너 문서가 권고하는 자원 배분은 모든 컨테이너에 최소 CPU 2코어와 메모리 4GB입니다. 가용성을 위해 웹 컨테이너는 최소 두 개를 띄우고, 어느 쪽이든 CPU 사용률이 50퍼센트를 넘으면 인스턴스를 늘리라고 합니다.

저장소 쪽 권고는 3편에서 정리한 대로입니다. ClickHouse는 샤드 1개에 복제본 3개 이상, Postgres는 v4에서 최소 15와 16 권장, Redis는 7.2 권장입니다.

마이그레이션 정책도 프로덕션에서는 다시 생각할 필요가 있습니다. 기본값은 기동 시 자동 마이그레이션입니다. 여러 인스턴스가 동시에 뜨는 환경이나 스키마 변경을 배포와 분리하고 싶은 경우에는 LANGFUSE_AUTO_POSTGRES_MIGRATION_DISABLEDLANGFUSE_AUTO_CLICKHOUSE_MIGRATION_DISABLED를 켜고 별도 단계로 돌립니다. ClickHouse 문서는 수동 마이그레이션 절차로 저장소를 받아 ./packages/shared/clickhouse/migrations/clustered/ 아래의 SQL에서 클러스터 이름을 조정한 뒤 실행하라고 안내합니다.

마치며 — 순서가 곧 진단이다

배포 순서를 저장소부터 애플리케이션으로 잡으면 문제가 생겨도 범위가 좁습니다. 저장소 넷을 먼저 세워 healthy를 확인하고, 시크릿 네 개를 만들어 넣고, 연결 문자열을 채우고, 그다음 애플리케이션을 올립니다. 마지막으로 트레이스를 한 건 보내 전체 경로를 검증합니다.

지금 할 수 있는 점검은 시크릿 관리입니다. SALTENCRYPTION_KEY가 compose 파일이나 값 파일에 평문으로 남아 있다면, 그것을 시크릿 저장소로 옮기는 일이 다음 배포보다 먼저입니다. 다음 글에서는 이렇게 세운 시스템이 트래픽을 받기 시작할 때 비용이 어디서 늘어나는지를 봅니다.

직접 해보기

  • HTTP 요청 빌더 (cURL 생성기) — 첫 기동 확인용 헬스 체크 요청을 만들어 두면 배포 스크립트에 그대로 넣을 수 있습니다.
  • PostgreSQL 놀이터 — 마이그레이션 계정과 애플리케이션 계정의 권한을 나누는 연습을 해 보세요.

시리즈

참고 자료

현재 단락 (1/130)

3편에서 구성 요소를 봤습니다. 웹과 워커 컨테이너, 그리고 Postgres, ClickHouse, Redis, 오브젝트 스토리지입니다. 이번 글은 그것들을 실제로 세우는 쪽입니다...

작성 글자: 0원문 글자: 8,201작성 단락: 0/130