Langfuse को अपने VPS पर कैसे host करें
अपने VPS पर Langfuse को self-host करने का पूरा तरीका जानें। इसमें ClickHouse डेटा रिटेंशन, TLS सेटअप, इमेज टैग्स और सुरक्षित बैकअप लेने की सटीक प्रक्रिया समझाई गई है।
AI agent को trace क्यों करें
आप Langfuse को self-host करते हैं ताकि यह देख सकें कि आपके agent ने वास्तव में एक run के दौरान क्या किया। Langfuse एक open source LLM (large language model) observability tool है। यह हर prompt, हर model response, हर tool call और हर token को record करता है, फिर उन्हें एक trace के अंतर्गत group करता है जिसे आप खोलकर पढ़ सकते हैं। इसे अपने VPS पर चलाने का अर्थ है कि वे prompts कभी भी आपके नियंत्रण वाले सर्वर से बाहर नहीं जाते।
इसकी आवश्यकता स्पष्ट है। आप किसी cost problem या quality problem को ठीक नहीं कर सकते जिसे आप देख नहीं सकते। एक provider invoice आपको बताती है कि मंगलवार का खर्च सोमवार की तुलना में चार गुना था। एक trace आपको बताती है कि किस agent run ने ऐसा किया, कौन सा prompt बढ़कर 40,000 tokens का हो गया, और कौन सा retry loop नौ बार चलने के बाद विफल हुआ। Invoice आपको केवल संख्या देती है। Trace आपको वह code देती है जिसने उसे उत्पन्न किया।
इस guide में तीन शब्दों का प्रयोग किया गया है। Trace आपके agent का एक end-to-end run है। Observation उस run के भीतर का एक step है: सामान्य code के लिए एक span, और model को की गई call के लिए एक generation। Score एक trace से जुड़ी संख्या है, जो human review या automated evaluator से प्राप्त होती है। Langfuse, OpenTelemetry (OTel) का उपयोग करता है, जो distributed tracing के लिए vendor-neutral standard है, इसलिए जो instrumentation आपके पास पहले से मौजूद है, वह इसकी ओर point कर सकता है।
Langfuse वास्तव में क्या self-host करता है
Langfuse v4 केवल एक container नहीं है। यह दो application containers और चार storage services का समूह है, और एक ही VPS पर ये सभी छह components आपके सर्वर पर चलते हैं।
langfuse-webवेब इंटरफेस और ingestion API को सर्व करता है।langfuse-workerबैकग्राउंड में queue को खाली करता है। यह ingestion batches को पार्स करता है, लागत की गणना करता है, और nightly retention job को चलाता है।- Postgres ट्रांजैक्शनल डेटा जैसे कि users, organisations, projects, API keys और prompts को स्टोर करता है।
- ClickHouse वास्तविक trace डेटा को रखता है, जिसमें observations और scores शामिल हैं। यह analytical queries के लिए बना एक column store है, यही कारण है कि दस करोड़ rows वाला डैशबोर्ड भी तेजी से परिणाम देता है।
- Redis वह queue और cache है जो वेब और वर्कर के बीच स्थित होता है।
- MinIO आपको सर्वर पर S3 compatible object storage प्रदान करता है। यह हर आने वाले raw event और आपके द्वारा अटैच की गई किसी भी मीडिया फाइल को स्टोर करता है।
Langfuse उन तीन घटकों के लिए न्यूनतम संसाधनों की आवश्यकता बताता है जो मुख्य कार्य करते हैं।
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 cores, 16 GiB मेमोरी और लगभग 100 GiB स्टोरेज वाली मशीन की सिफारिश करती है, जो इस गणना के अनुरूप है।
इसे 2 GiB वाले प्लान पर चलाने का प्रयास न करें। ClickHouse शुरू तो हो जाएगा और कुछ समय तक writes स्वीकार करेगा, लेकिन बैकग्राउंड मर्ज के दौरान बंद हो जाएगा, क्योंकि मर्ज प्रक्रिया टेबल के बड़े हिस्सों को मेमोरी में लोड करती है। आप देखेंगे कि docker compose ps, clickhouse कंटेनर को restarting के रूप में रिपोर्ट कर रहा है, dmesg में Out of memory: Killed process 1234 (clickhouse-serv) जैसी लाइन दिखाई देगी, और हर Langfuse डैशबोर्ड 500 एरर देगा। कम दबाव में ClickHouse क्वेरी को अस्वीकार कर देगा और DB::Exception: Memory limit (total) exceeded लॉग करेगा। एक डेवलपर के लिए जो प्रतिदिन कुछ हजार traces भेजता है, 8 GiB काम कर सकता है। 16 GiB वह संख्या है जिसके लिए आपको योजना बनानी चाहिए। यदि उसी VPS पर कुछ और भी चलाना है, तो उसके लिए अलग से बजट रखें, क्योंकि एक self-hosted AFFiNE workspace जैसा अपेक्षाकृत हल्का स्टैक भी अपनी अलग मेमोरी चाहता है और ClickHouse अपनी मेमोरी वापस नहीं छोड़ेगा।
Docker Compose के साथ Langfuse को Deploy करें
Repository को clone करें। Stack, wiring और default environment सभी इसके docker-compose.yml में मौजूद हैं।
git clone https://github.com/langfuse/langfuse.git
cd langfuseआपको जिन भी values को बदलना है, उन्हें उस file में # CHANGEME के रूप में चिह्नित किया गया है। सबसे पहले तीन application secrets generate करें।
openssl rand -base64 32 # NEXTAUTH_SECRET
openssl rand -base64 32 # SALT
openssl rand -hex 32 # ENCRYPTION_KEYENCRYPTION_KEY को 64 hex characters के रूप में 256 bits का होना चाहिए, जो कि ठीक वही है जो openssl rand -hex 32 print करता है। यह sensitive values को at rest encrypt करता है, जिसमें आपके द्वारा instance में store की गई कोई भी LLM provider keys शामिल हैं। data मौजूद होने के बाद इसे बदलने पर वे rows decrypt नहीं हो पाएंगी, इसलिए इसे पहली boot से ही permanent मानें। SALT का उपयोग आपकी Langfuse API keys को hash करने के लिए किया जाता है, इसलिए इसे बदलने से वे सभी keys अमान्य हो जाएंगी जिनका उपयोग आपके agents पहले से कर रहे हैं।
इसके बाद POSTGRES_PASSWORD, CLICKHOUSE_PASSWORD, REDIS_AUTH और MINIO_ROOT_PASSWORD को set करें। MinIO password चार स्थानों पर दिखाई देता है: एक बार 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 उस client को SignatureDoesNotMatch के साथ reject कर देगा, जो worker log में दिखाई देगा जबकि web interface सामान्य दिखेगा। इन values को tracked compose file के बजाय env file में रखना वह pattern है जिसे Docker Compose env files and secrets में कवर किया गया है।
शुरू करने से पहले image tags को pin करें
दी गई file langfuse/langfuse:4 और langfuse/langfuse-worker:4 का उपयोग करती है। वे tags बदलते रहते हैं। Langfuse अपनी Postgres और ClickHouse migrations को start होते ही automatically run करता है, इसलिए महीनों बाद किया गया एक routine docker compose pull उस database पर अनियोजित schema migration बन जाता है जिसका आपने उस सुबह backup नहीं लिया था। दोनों को एक docker-compose.override.yml में किसी release पर pin करें, जिसे Compose दी गई file के ऊपर merge कर देता है ताकि बाद का git pull आपके edits के साथ conflict न करे।
services:
langfuse-web:
image: docker.io/langfuse/langfuse:4.3.1
langfuse-worker:
image: docker.io/langfuse/langfuse-worker:4.3.1August 2026 तक Version 4.3.1 वर्तमान 4.3 release थी (4.4.0 तब से आ चुकी है)। project के GitHub releases page को देखें, जिस दिन आप deploy कर रहे हैं उस दिन जो current हो उसे pin करें, और फिर उस number को सोच-समझकर बदलें। दी गई file में storage images पहले से ही majors, postgres:17, clickhouse-server:25.12 और redis:7 पर pinned हैं, और वे भी समान treatment की हकदार हैं। यह नियम केवल Langfuse के लिए विशिष्ट नहीं है: एक self-hosted openGym workout tracker इस stack का एक छोटा हिस्सा चलाता है और फिर भी उसे एक named git tag की आवश्यकता होती है, क्योंकि जो कुछ भी start होते ही अपना database migrate करता है, वह एक routine pull को schema change में बदल सकता है।
इसे up करें।
docker compose up -d
docker compose ps
docker compose logs -f langfuse-workerFirst boot migrations को run करता है, इसलिए किसी भी response के आने से पहले एक या दो मिनट का समय दें। docker compose ps को running state में छह services की सूची दिखानी चाहिए। यदि worker loop में restart होता है, तो उसके log में कारण होता है: CLICKHOUSE_MIGRATION_URL port 9000 पर ClickHouse native protocol का उपयोग करता है, न कि HTTP port 8123 का, और इसे 8123 पर point करने से वहां failure होता है जबकि web container ठीक दिखता है।
Box से ही health की जाँच करें।
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 call केवल यह साबित करती है कि API process जीवित है, क्योंकि यह जानबूझकर database को skip करती है ताकि Postgres blips के दौरान भी service चलती रहे। failIfDatabaseUnavailable=true form वह है जिसे monitor पर point करना सार्थक है, और database के unreachable होने पर यह 503 return करता है। migrations पूरी होने और container के traffic स्वीकार करने के बाद /api/public/ready 200 return करता है। दोनों साधारण HTTP checks हैं, इसलिए एक Uptime Kuma status page उन्हें watch कर सकता है और आपके agents के पता लगाने से पहले ही आपको बता सकता है कि stack down है।
TLS को सामने रखें और अतिरिक्त ports बंद करें
प्रदान की गई compose file वेब container के लिए 3000:3000 और MinIO के लिए 9090:9000 को publish करती है। दोनों ही हर interface पर bind होते हैं। एक public IP पर इसका मतलब है कि port 3000 को scan करने वाला कोई भी व्यक्ति आपके sign up page तक पहुँच सकता है, और 9090 को scan करने वाला कोई भी व्यक्ति उस bucket से बात कर रहा है जिसमें आपके raw prompts मौजूद हैं।
केवल एक firewall rule इन्हें बंद नहीं करता है। Docker अपने स्वयं के DNAT rules को nat table में लिखता है, और ufw के filter rules के पैकेट देखने से पहले ही उनका मूल्यांकन हो जाता है, इसलिए ufw deny 3000 published port को खुला छोड़ देता है। यह समस्या इतने लोगों को प्रभावित करती है कि इसके लिए एक अलग guide मौजूद है: Docker published ports ufw को क्यों bypass करते हैं। इसके बजाय अपनी override file में loopback पर bind करें।
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 सहित सटीक public address होना चाहिए, क्योंकि login flow उसी मान से अपना callback URL बनाता है। यदि आप इसे HTTPS proxy के पीछे http://localhost:3000 ही रहने देते हैं, तो sign in round trip browser को ऐसी जगह भेज देगा जहाँ वह पहुँच नहीं सकता।
अब एक reverse proxy को 127.0.0.1:3000 की ओर point करें और certificate को उसी पर रहने दें। उसी Compose project में Traefik का उपयोग करना एक सामान्य विकल्प है, और routing labels वही हैं जो एक Traefik reverse proxy के पीछे कई apps चलाना में बताए गए हैं। यदि server पर केवल Langfuse चल रहा है, तो Caddy दो lines में वही काम कर देता है। curl -sI https://langfuse.example.com/api/public/ready के साथ verify करें, फिर किसी दूसरे machine से पुष्टि करें कि curl http://YOUR_IP:3000 अब time out हो रहा है।
MinIO के संबंध में एक सावधानी बरतें। Langfuse आपके browser को उस S3 endpoint की ओर इशारा करने वाले presigned URLs के माध्यम से attached media serve करता है। इसलिए, यदि आप images या audio वाले multi-modal traces का उपयोग करते हैं, तो केवल loopback पर सीमित MinIO का मतलब होगा कि वे attachments load नहीं होंगी। इसे proxy करने से पहले blob storage configuration page को पढ़ें, क्योंकि presigned URL में लिखा गया endpoint आपके द्वारा publish किए गए endpoint से मेल खाना चाहिए। Plain text traces इससे प्रभावित नहीं होते हैं।
पहली बार visit करने पर अपना account बनाएँ, और फिर instance को अपने तक सीमित रखें। LANGFUSE_ALLOWED_ORGANIZATION_CREATORS को अपने email address पर set करें, ताकि page तक पहुँचने वाला कोई अनजान व्यक्ति आपके server पर organization न बना सके। यदि आप पहले से ही Authentik को अपने identity provider के रूप में चला रहे हैं, तो Langfuse एक standard OIDC connection स्वीकार करता है। इससे accounts आपके अन्य apps के साथ manage होते हैं, न कि केवल इस box की password list में सीमित रहते हैं।
अपना पहला ट्रेस भेजें
वेब इंटरफेस में एक प्रोजेक्ट बनाएँ और प्रोजेक्ट सेटिंग्स से अपनी पब्लिक और सीक्रेट की (keys) कॉपी करें। 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, SDK v4 में वेरिएबल का नाम है, जिसे मार्च 2026 में रिलीज किया गया था। पुराना कोड और पुरानी गाइड्स LANGFUSE_HOST का उपयोग करती हैं। यदि आपके ट्रेसेस आपके सर्वर के बजाय Langfuse Cloud पर जा रहे हैं, तो इसका कारण unset बेस URL है, क्योंकि डिफ़ॉल्ट मान होस्टेड इंस्टेंस की ओर इशारा करता है।
pip install langfuse opentelemetry-instrumentation-anthropic anthropicimport 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 डेकोरेटर फंक्शन के चारों ओर एक ऑब्जर्वेशन खोलता है, इसके आर्गुमेंट्स और रिटर्न वैल्यू को कैप्चर करता है, और इसे किसी भी सक्रिय ऑब्जर्वेशन के अंतर्गत नेस्ट (nest) कर देता है। AnthropicInstrumentor, Anthropic क्लाइंट के लिए OpenTelemetry इंस्ट्रूमेंटेशन है, और यह प्रत्येक messages.create कॉल को एक जनरेशन में बदल देता है जिसमें मॉडल का नाम, टोकन उपयोग और लेटेंसी शामिल होती है, बिना कॉल साइट में किसी बदलाव के।
दो calls आपके लिए जाँच कर देती हैं। langfuse.auth_check() गलत keys या गलत base URL होने पर False लौटाता है। यह dashboard खाली क्यों है, इसका अनुमान लगाने से अधिक तेज़ है। langfuse.flush() queued spans भेजे जाने तक execution को रोकता है। यह short lived processes के लिए आवश्यक है, क्योंकि SDK background में batching करता है और तुरंत exit होने वाली script अपने unsent batch को साथ ले जाती है। यदि एक script के बजाय पूरी team traces भेज रही है, तो इन तीनों variables को प्रत्येक व्यक्ति के shell में सेट करने के बजाय उस gateway में एक बार सेट करें, जिसके माध्यम से सभी agents पहले से चल रहे हैं। इसी तरह self-hosted OneCLI harness प्रत्येक colleague के runs को instrumented रखता है और keys को एक ही स्थान पर रखता है।
ClickHouse का आकार लगातार क्यों बढ़ता है?
Traces सबसे तेजी से बढ़ने वाला डेटा है जिसे अधिकांश लोग स्वयं होस्ट करते हैं। प्रत्येक agent run हर चरण के लिए एक पंक्ति लिखता है, और इनपुट व आउटपुट को पूर्ण रूप से स्टोर किया जाता है। इसलिए, लंबे प्रॉम्प्ट वाला एक सक्रिय agent उस एप्लिकेशन की तुलना में प्रतिदिन कहीं अधिक बाइट्स उत्पन्न करता है जिसकी वह निगरानी कर रहा है। यदि इसे ऐसे ही छोड़ दिया जाए, तो ClickHouse डिस्क को भर देता है, और डिस्क भर जाने पर ingestion धीमा होने के बजाय पूरी तरह रुक जाता है।
यहाँ दो अलग-अलग चीजें बढ़ती हैं, और उन्हें दो अलग-अलग समाधानों की आवश्यकता होती है।
पहली चीज आपका अपना trace डेटा है, और इसका समाधान retention सेटिंग है। वेब इंटरफेस में project settings खोलें और दिनों में डेटा retention अवधि सेट करें। Langfuse कम से कम 3 दिनों की अनुमति देता है। इसके बाद एक nightly job उस अवधि से पुराने traces, observations, scores और media assets का चयन करती है और उन्हें ClickHouse व blob storage से हटा देती है। इस job को bucket पर DeleteObject अनुमति की आवश्यकता होती है, जो डिफ़ॉल्ट compose फ़ाइल में MinIO root credentials के पास पहले से होती है। विलोपन स्थायी होता है, इसलिए यदि आपको दीर्घकालिक इतिहास की आवश्यकता है तो पहले blob storage export कॉन्फ़िगर करें। Langfuse की अपनी तालिकाओं पर मैन्युअल रूप से TTL clauses न लिखें: retention job ही ClickHouse और bucket को तालमेल में रखती है, और मैन्युअल TTL केवल एक तरफ का डेटा हटाता है।
आप वास्तव में जितना उपयोग करते हैं, उसके आधार पर विंडो चुनें। लागत और गुणवत्ता की समीक्षा कुछ दिन पुराने डेटा पर होती है, न कि महीनों पुराने डेटा पर। एक छोटी टीम के लिए 30 दिन एक उचित शुरुआत है, और यदि आप केवल तब trace खोलते हैं जब कुछ खराब होता है, तो 14 दिन पर्याप्त हैं।
दूसरी चीज ClickHouse की अपनी system log तालिकाएं हैं, और यह लोगों को आश्चर्यचकित करती है, क्योंकि retention कॉन्फ़िगर होने के बाद भी डिस्क बढ़ती रहती है। ClickHouse अपने स्वयं के डायग्नोस्टिक्स के लिए trace_log, text_log, opentelemetry_span_log, metric_log और asynchronous_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" के साथ चलाएं। यदि system तालिकाएं सूची में सबसे ऊपर हैं, तो उन्हें config overlay के साथ बंद कर दें, क्योंकि ClickHouse स्टार्टअप पर /etc/clickhouse-server/config.d/ में मौजूद प्रत्येक फ़ाइल को अपनी मुख्य config के ऊपर मर्ज करता है।
<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 scaling दस्तावेज़ों में विस्तार से बताया गया है।
एक और तालिका है जिसके बारे में जानना उपयोगी है। blob_storage_file_log आपकी bucket पर अपलोड की गई event फ़ाइलों को ट्रैक करती है। यदि आप bucket पर lifecycle policy भी सेट करते हैं, तो तालिका को एक मेल खाता हुआ TTL दें ताकि दोनों में अंतर न आए।
ALTER TABLE blob_storage_file_log MODIFY TTL created_at + INTERVAL 30 DAY DELETE;डेटा डिस्क पर एक साधारण df -h अलर्ट भी लगाएं। Traces सुचारू रूप से नहीं बढ़ते हैं। वे उस दिन बढ़ते हैं जिस दिन आप एक नया agent शिप करते हैं, और इसका पहला संकेत ingestion का विफल होना नहीं होना चाहिए।
Postgres और ClickHouse का बैकअप लेना
Langfuse बैकअप के तीन हिस्से होते हैं। Postgres में आपके users, organisations, projects और API keys सुरक्षित रहते हैं। ClickHouse में traces होते हैं। MinIO में raw events होते हैं। यदि आप केवल Postgres को restore करते हैं, तो आप login तो कर पाएंगे लेकिन कोई history नहीं दिखेगी। यदि आप केवल ClickHouse को restore करते हैं, तो history तो होगी लेकिन कोई भी उसे देखने के लिए login नहीं कर पाएगा। यह विभाजन केवल Langfuse तक सीमित नहीं है; self-hosted Chatwoot support desk का ढांचा भी ऐसा ही है, जहाँ uploads directory के बिना लिया गया Postgres dump उन conversations को तो restore कर देता है, लेकिन उनके attachments गायब हो जाते हैं।
Postgres एक साधारण pg_dump है, जिसकी Langfuse बैकअप docs में अनुशंसा की गई है।
docker compose exec -T postgres pg_dump -U postgres postgres \
| gzip > langfuse-pg-$(date +%F).sql.gzClickHouse के लिए अधिक सावधानी की आवश्यकता होती है, क्योंकि merges चलने के दौरान copy की गई live data directory एक consistent बैकअप नहीं होती है। एक ही सर्वर पर इसका सरल तरीका यह है कि container को stop करें और volume को archive कर लें।
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 clickhousedocker volume ls द्वारा print किए गए volume name का उपयोग करें, न कि YAML में लिखे गए नाम का। file में langfuse_clickhouse_data घोषित होता है, और Compose इसमें project name का prefix जोड़ देता है, इसलिए langfuse नामक directory में clone करने पर langfuse_langfuse_clickhouse_data प्राप्त होता है। यदि आप इसमें गलती करते हैं, तो docker run बिना किसी चेतावनी के एक नया खाली volume बना देगा और आपका archive खाली रह जाएगा।
Web container worker द्वारा process किए जाने से पहले हर incoming event को bucket में लिखता है, इसलिए ClickHouse को थोड़ी देर के लिए stop करने का मतलब है कि worker बाद में retry कर लेगा। इसे शांत घंटों (quiet hour) में करें और समय कम रखें। अधिक व्यस्त instance के लिए, ClickHouse का अपना BACKUP DATABASE default TO S3(...) statement सर्वर को stop किए बिना एक consistent बैकअप तैयार कर देता है। MinIO तीसरा हिस्सा है, और mc mirror या MinIO replication का उपयोग करके इसे off-box bucket पर सुरक्षित किया जा सकता है। आप जो भी बैकअप लें, उसे सर्वर से बाहर निकालें, जिसके लिए VPS पर encrypted restic backups का उपयोग किया जाता है।
Redis के बैकअप की आवश्यकता नहीं होती है। इसमें queue और cache होता है, इसलिए इसे खोने का मतलब केवल उन events का नुकसान है जो उस समय process हो रहे थे, पुराना डेटा सुरक्षित रहता है।
Consistency की चेतावनी वास्तविक है और इसे स्पष्ट रूप से समझना आवश्यक है। Postgres और ClickHouse के dumps अलग-अलग समय पर लिए जाते हैं, इसलिए restore करने पर ऐसा हो सकता है कि कोई project row तो हो लेकिन traces न हों, या ऐसे traces हों जिनका project अब मौजूद ही न हो। Langfuse इसे सहन कर लेता है, लेकिन दोनों dumps को एक-दूसरे के करीब और कम traffic वाले समय में लें। Event bucket ही असली सुरक्षा कवच है, क्योंकि Langfuse processing से पहले हर incoming event को वहां सुरक्षित कर लेता है।
कम से कम एक बार scratch stack में restore करके जरूर देखें। इसी तरह आपको गलत volume name का पता अभी चल जाएगा, न कि किसी outage के दौरान।
सबसे पहले क्या देखें
पहले सप्ताह में चार चीजें महत्वपूर्ण होती हैं।
- प्रति ट्रेस लागत (Cost per trace): Langfuse मॉडल के नाम और टोकन उपयोग के आधार पर लागत की गणना करता है। इसलिए, ट्रेसेस को लागत के अनुसार क्रमबद्ध करें और सबसे महंगे ट्रेस को शुरू से अंत तक पढ़ें। इसका कारण आमतौर पर एक बढ़ता हुआ प्रॉम्प्ट होता है: संदर्भ (context) में पेस्ट किया गया पूरा दस्तावेज़, या बातचीत का ऐसा इतिहास जिसे कोई ट्रिम नहीं करता। एक बार जब आप इसे देख लेते हैं, तो AI एजेंट की लागत को नियंत्रित करना अनुमान लगाने के बजाय एक इंजीनियरिंग कार्य बन जाता है।
- इनपुट और आउटपुट के आधार पर टोकन उपयोग का विभाजन: इनपुट टोकन संख्या में अधिक और सस्ते होते हैं, आउटपुट टोकन कम और महंगे होते हैं, और कैश किया गया इनपुट और भी सस्ता होता है। यही हिसाब Claude Code टोकन उपयोग की गणना कैसे की जाती है में समझाया गया है, और यह आपके द्वारा लिखे गए किसी भी एजेंट पर लागू होता है।
- लेटेंसी पर्सेंटाइल (Latency percentiles): माध्यिका (median) समस्या को छिपा देती है। p95 और p99 वे स्थान हैं जहाँ टाइमआउट होते हैं, और एक एजेंट लूप के भीतर, p95 पर एक धीमा टूल कॉल पुनरावृत्तियों (iterations) की संख्या से गुणा हो जाता है।
- विफल टूल कॉल (Failed tool calls): ऑब्जर्वेशन को
ERRORस्तर के आधार पर फ़िल्टर करें। जो टूल 5% समय विफल होता है, वह कुल सफलता दर में अदृश्य रहता है, लेकिन ट्रेसेस में बहुत स्पष्ट दिखाई देता है, जहाँ आप मॉडल को पुनः प्रयास करते हुए और फिर उसे ठीक करने के लिए टोकन खर्च करते हुए देखते हैं।
रिटेंशन विंडो सेट करें और वह डैशबोर्ड चुनें जिसे आप हर सप्ताह उसी दिन चेक करेंगे जिस दिन आप डिप्लॉय करते हैं। एक ऑब्जर्वेबिलिटी टूल जिसे कोई नहीं खोलता, वह केवल एक डेटाबेस है जो डिस्क को भरता है।
FAQ
self-hosted Langfuse के लिए कितनी memory की आवश्यकता होती है?
4 CPU cores और 16 GiB memory की योजना बनाएँ, जो कि एक single virtual machine के लिए Langfuse Docker Compose गाइड द्वारा अनुशंसित है, साथ ही लगभग 100 GiB storage की आवश्यकता होगी। प्रकाशित component minimums में ClickHouse के लिए 8 GiB और web व worker containers के लिए 4 GiB प्रत्येक की आवश्यकता है, और Postgres, Redis तथा MinIO के लिए इसके अतिरिक्त memory चाहिए। Eight GiB पर एक developer का instance चल सकता है। Two GiB पर यह नहीं चलेगा: background merges के दौरान kernel द्वारा ClickHouse को kill कर दिया जाता है, और dmesg में Out of memory: Killed process दिखाई देता है।
data retention सेट करने के बाद भी मेरा ClickHouse disk क्यों भर जाता है?
Retention setting केवल Langfuse के अपने data को कवर करती है। ClickHouse अलग से अपनी diagnostic tables trace_log, text_log, opentelemetry_span_log, metric_log और asynchronous_metric_log लिखता है, और ये बिना किसी TTL के आते हैं। यह देखने के लिए कि कौन सी table सबसे बड़ी है, table के अनुसार group करके system.parts query चलाएँ, फिर /etc/clickhouse-server/config.d/ के अंतर्गत एक file में remove="1" entry के साथ unused tables को disable करें, ClickHouse को restart करें, और पहले से उपयोग की गई space को reclaim करने के लिए existing tables को drop करें।
Langfuse में न्यूनतम data retention अवधि क्या है?
तीन दिन। Retention को project settings में या projects API के माध्यम से प्रति project सेट किया जाता है, और एक nightly job ClickHouse और blob storage दोनों से उस window से पुराने traces, observations, scores और media assets को delete कर देती है। Deletion को undo नहीं किया जा सकता है, इसलिए यदि आपको उस window से अधिक पुराना history चाहिए तो पहले blob storage export configure करें।
क्या मुझे Postgres और ClickHouse दोनों का backup लेना होगा?
हाँ, क्योंकि वे अलग-अलग चीजें रखते हैं। Postgres users, organisations, projects और API keys को रखता है, और ClickHouse स्वयं trace data को रखता है। केवल Postgres को restore करने पर आपको एक ऐसा instance मिलेगा जिसमें आप login तो कर सकते हैं लेकिन उसमें कुछ भी नहीं होगा। MinIO bucket का भी backup लें, क्योंकि यह उन raw events को रखता है जिन्हें Langfuse आने पर persist करता है, जो stack में source of truth के सबसे करीब है।
क्या मैं existing OpenTelemetry setup को self-hosted Langfuse पर point कर सकता हूँ?
हाँ। Langfuse v4 और इसके v4 SDKs OpenTelemetry पर आधारित हैं, और Anthropic तथा OpenAI OTel instrumentations सीधे इस पर export करते हैं। Python में, pip install langfuse opentelemetry-instrumentation-anthropic चलाएँ, startup पर एक बार AnthropicInstrumentor().instrument() call करें, और LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY तथा LANGFUSE_BASE_URL को अपने host पर सेट करें। missing dashboard की तलाश करने से पहले langfuse.auth_check() के साथ पुष्टि करें।