VPS पर mem0 को self-host कैसे करें: पूरी गाइड
अपने VPS पर mem0 memory server को self-host करने का तरीका जानें। इसमें 1GB RAM की न्यूनतम आवश्यकता, Docker Compose सेटअप, TLS कॉन्फ़िगरेशन और Ollama के साथ स्थानीय एकीकरण शामिल है।
VPS पर mem0 को self-host करने की वास्तविक RAM लागत
mem0 को self-host करने का अर्थ है तीन containers चलाना: FastAPI memory server, pgvector extension के साथ Postgres, और एक Next.js dashboard। mem0 agents के लिए एक memory layer है। आप इसमें एक conversation post करते हैं, एक language model उस conversation से स्थायी तथ्यों (durable facts) को निकालता है, और उन तथ्यों को vectors के रूप में store किया जाता है ताकि बाद में query करने पर प्रासंगिक जानकारी वापस मिल सके।
इन तीन containers के लिए लगभग 1 GB resident memory और images build होने के बाद 3 से 4 GB disk space का बजट रखें। यदि language model कहीं और चल रहा हो, तो 2 GB का VPS इसे आसानी से चला सकता है। जब model Ollama के माध्यम से उसी box पर चलता है, तो model बाकी सब पर हावी हो जाता है: 4 bits पर quantised एक 8B model को अकेले ही लगभग 6 GB RAM चाहिए होती है, इसलिए पूरी तरह से local build के लिए 8 GB से शुरुआत करनी पड़ती है।
इन आंकड़ों को किसी blog post से, इसे भी शामिल करते हुए, अंतिम न मानें। आपने जो stack वास्तव में build किया है, उसे मापें।
docker compose ps
docker stats --no-stream
docker system df -vdocker stats प्रत्येक container की resident memory को print करता है। docker system df -v प्रत्येक image और volume द्वारा ली गई disk space को print करता है।
Steady state peak नहीं होता है। docker compose up -d --build Next.js dashboard को compile करता है, और वह Node build पूरी install प्रक्रिया का सबसे अधिक संसाधन लेने वाला क्षण होता है। 1 GB के VPS पर kernel का out-of-memory killer इसे रोक देता है और build exit code 137 के साथ समाप्त हो जाता है। Docker bug खोजने से पहले कारण की पुष्टि करें:
dmesg -T | grep -i "killed process"यदि आपको लगता है कि आपकी आवश्यकता के लिए सर्वर बहुत भारी machinery है, तो छोटे विकल्प भी मौजूद हैं। बिना किसी सर्वर के local agent memory store और Claude Code के भीतर रहने वाली memory दोनों ही database के उपयोग से बचते हैं। जब कई agents, या कई machines को एक ही memory को पढ़ने की आवश्यकता हो, तब यहाँ वापस आएँ।
क्या mem0 graph memory के लिए मुझे Neo4j की आवश्यकता है?
नहीं। यदि कोई गाइड आपको Neo4j container जोड़ने के लिए कहती है, तो वह गाइड कोड से पुरानी है।
mem0 में graph memory का अर्थ पहले एक बाहरी graph database होता था, जिसे graph_store key के अंतर्गत और enable_graph को true पर सेट करके कॉन्फ़िगर किया जाता था। अप्रैल 2026 में जारी किए गए नए memory algorithm ने open source SDK से इन दोनों keys को हटा दिया है। Entity extraction अब सामान्य add path के भीतर चलता है, और entities को आपके मुख्य collection के नाम के साथ _entities जोड़कर एक दूसरे pgvector collection में लिखा जाता है। इसमें कोई migration चलाने की आवश्यकता नहीं है। Built-in entity linking अगली add call पर काम करना शुरू कर देता है।
Graph store को हटाने से एक JVM container, उसकी heap, और कई सौ megabytes की image की बचत होती है। 2 GB के VPS पर यह running और swapping के बीच का अंतर है।
यहाँ बताया गया है कि आप क्या छोड़ रहे हैं, स्पष्ट रूप से: Search results में पहले एक relations field होता था जो entities के बीच edges की सूची देता था। वह field अब हटा दिया गया है। Entity matches अब combined score में memory की स्थिति को ऊपर ले जाते हैं, और इसमें ऐसी कोई संरचना नहीं है जिसे आप traverse कर सकें। यदि आपका application उन relationships को walk करता था, तो mem0 अब उन्हें hold नहीं करता है, और आपको mem0 के बाहर अपना स्वयं का graph database रखना होगा, जिसे आपके अपने कोड द्वारा feed किया जाएगा।
रिपॉजिटरी में मौजूद compose file एक development compose है
server/docker-compose.yaml, name: mem0-dev को घोषित करता है, और इसका अर्थ वही है। इसे चलाने से पहले पढ़ें, क्योंकि इसमें मौजूद पांच चीजें सर्वर के लिए गलत हैं।
- यह
server/dev.Dockerfileसे build होता है और.:/appके साथ आपके checkout को image के ऊपर mount करता है, इसलिए container आपके द्वारा build की गई चीज़ के बजाय उस directory में मौजूद किसी भी चीज़ को चलाता है। - इसकी command
rm -rf /app/packages && pip install -q --force-reinstall --no-deps mem0ai && alembic upgrade head && uvicorn main:app --reloadहै। यह हर start पर PyPI सेmem0aiको फिर से install करती है, इसलिए आपके सर्वर पर चलने वाला version उस restart के दौरान बदल सकता है जिसे आपने upgrade नहीं माना था। - उसी pip step का मतलब है कि बिना outbound network के किया गया restart, uvicorn के चलने से पहले ही fail हो जाएगा। आपका memory server तब down हो जाता है क्योंकि PyPI तक पहुँचा नहीं जा सका।
--reload, uvicorn के file watcher को start करता है। यह code edit करने पर process को restart करने के लिए होता है, और production में बिना किसी उपयोगी काम के यह memory और एक अतिरिक्त process की खपत करता है। ProductionDockerfileमें भी उसकेCMDमें--reloadहोता है, इसलिए आप किसी भी तरह command को override कर देते हैं।- published ports
"8888:8000","8432:5432"और"3000:3000"हैं। बिना किसी address के published port,0.0.0.0पर bind हो जाता है, इसलिए stack शुरू होते ही Postgres 8432 पर public internet को जवाब देने लगता है।
यह आखिरी बिंदु अपनी चेतावनी का हकदार है। Docker, ufw द्वारा प्रबंधित chain से पहले अपने स्वयं के rules लिखकर port publish करता है, इसलिए ufw deny 8432 किसी published container port को बंद नहीं करता है। Docker publishing ports straight past ufw इसमें शामिल rules के बारे में विस्तार से बताता है।
एक वास्तविक सर्वर के लिए compose file
server/ के अंदर काम करें, init-db.sh को वहीं रहने दें, और docker-compose.yaml को इससे बदलें।
name: mem0
services:
mem0:
build:
context: .
dockerfile: Dockerfile
restart: unless-stopped
env_file: .env
ports:
- "127.0.0.1:8888:8000"
networks: [mem0_network]
volumes:
- mem0_history:/app/history
depends_on:
postgres:
condition: service_healthy
command: >
sh -c "alembic upgrade head &&
uvicorn main:app --host 0.0.0.0 --port 8000"
environment:
- PYTHONUNBUFFERED=1
- DASHBOARD_URL=https://mem0.example.com
- APP_DB_NAME=mem0_app
- AUTH_DISABLED=false
- MEM0_TELEMETRY=false
postgres:
image: pgvector/pgvector:pg17
restart: unless-stopped
shm_size: "128mb"
networks: [mem0_network]
environment:
- POSTGRES_USER=${POSTGRES_USER:-postgres}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in .env}
healthcheck:
test: ["CMD-SHELL", "pg_isready -q -U ${POSTGRES_USER:-postgres}"]
interval: 5s
timeout: 5s
retries: 5
volumes:
- postgres_db:/var/lib/postgresql/data
- ./init-db.sh:/docker-entrypoint-initdb.d/init-db.sh
mem0-dashboard:
build: ./dashboard
restart: unless-stopped
ports:
- "127.0.0.1:3000:3000"
networks: [mem0_network]
environment:
- NEXT_PUBLIC_API_URL=https://mem0.example.com
- API_INTERNAL_URL=http://mem0:8000
depends_on:
mem0:
condition: service_started
volumes:
postgres_db:
mem0_history:
networks:
mem0_network:
driver: bridgeयहाँ पाँच बदलाव महत्वपूर्ण हैं, और हर एक का अपना कारण है।
प्रत्येक ports प्रविष्टि 127.0.0.1 से शुरू होती है, ताकि kernel उन connections को केवल उसी box से स्वीकार करे। बाहर से आने वाला सब कुछ reverse proxy के माध्यम से आता है, जो certificate रखने वाली एकमात्र चीज़ है।
Postgres में कोई ports ब्लॉक नहीं है। mem0 container उस तक service name द्वारा mem0_network पर पहुँचता है, इसलिए 8432 को publish करने से आपको कुछ नहीं मिलता और एक open port का जोखिम बढ़ता है। जब आपको shell की आवश्यकता हो तो docker compose exec postgres psql -U postgres का उपयोग करें।
History, ./history bind mount से हटकर एक named volume पर चली गई है। Bind mount डेटा को इस host पर एक path और एक uid से जोड़ता है, जबकि named volume एक ऐसा object है जिसे Docker snapshot कर सकता है और स्थानांतरित कर सकता है। Named volumes बनाम bind mounts में बताया गया है कि कौन सा कब सही है।
Command से --reload हट गया है और alembic upgrade head बना हुआ है। उस migration step को बनाए रखें। इसके बिना, app बिना tables वाले database के साथ boot होता है, और हर request पहली query पर ही fail हो जाती है।
NEXT_PUBLIC_API_URL वह URL है जिसे आपका browser call करता है, इसलिए यह public HTTPS address होना चाहिए, न कि http://mem0:8000। Next.js build time पर प्रत्येक NEXT_PUBLIC_ मान को inline कर देता है, इसलिए इसे बदलने के लिए docker compose up -d --build mem0-dashboard की आवश्यकता होती है। एक साधारण restart पुराने मान को JavaScript में ही रहने देता है और dashboard गलत host को call करता है।
Secrets .env में रहते हैं, और .env इंटरनेट से दूर रहता है
cd server
cp .env.example .env
openssl rand -hex 32 # paste into JWT_SECRET
openssl rand -hex 32 # paste into ADMIN_API_KEY
chmod 600 .envPOSTGRES_PASSWORD, JWT_SECRET और ADMIN_API_KEY को सेट करें। AUTH_DISABLED=false को वैसे ही रहने दें। यह नाम स्पष्ट करता है कि वह flag क्या करता है: यदि यह ऑन है, तो सर्वर अपनी पूरी मेमोरी उस व्यक्ति को दे देता है जो उस port तक पहुँच सकता है। यदि आप नहीं चाहते कि onboarding event upstream भेजा जाए, तो MEM0_TELEMETRY=false को सेट करें।
ADMIN_API_KEY की तुलना secrets.compare_digest के साथ X-API-Key header से की जाती है, और मैच होने पर हर database lookup को छोड़ दिया जाता है। यह पूरी API के लिए एक root credential है। इसे उसी तरह संभालें: shell history में न रखें, git में न डालें, और न ही इसे किसी prompt में paste करें। Compose env files और उनसे secrets कहाँ लीक होते हैं और API keys को agent के context से बाहर रखना दोनों यहाँ सीधे लागू होते हैं, क्योंकि इस सर्वर को कॉल करने वाले agents हैं।
env_file से लोड किए गए मान container environment में रहते हैं, और docker inspect उन्हें पूरा प्रिंट कर देता है। docker group का कोई भी व्यक्ति उन्हें पढ़ सकता है, और docker group का कोई भी व्यक्ति प्रभावी रूप से host पर root होता है।
API के सामने TLS लगाएँ, न कि 8888 port खोलें
API 127.0.0.1:8888 पर और dashboard 127.0.0.1:3000 पर जवाब देता है। nginx 443 पर TLS (transport layer security) को terminate करता है और दोनों पर traffic forward करता है।
server {
listen 443 ssl;
server_name mem0.example.com;
ssl_certificate /etc/letsencrypt/live/mem0.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mem0.example.com/privkey.pem;
location ~ ^/(memories|search|configure|auth|api-keys|docs|openapi.json) {
proxy_pass http://127.0.0.1:8888;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_read_timeout 180s;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}proxy_read_timeout दिखने से कहीं अधिक महत्वपूर्ण है। एक add call तब तक block रहती है जब तक language model conversation को पढ़कर facts extract नहीं कर लेता। CPU पर चलने वाला एक local 8B model अक्सर nginx के 60 second के default timeout से अधिक समय लेता है, और फिर caller को 504 Gateway Time-out दिखाई देता है जबकि model अभी भी काम कर रहा होता है और memory अभी भी लिखी जा रही होती है। अंत में आपके पास एक ऐसी memory होती है जिसके बारे में आपको बताया गया था कि वह fail हो गई है।
बाकी ports को default deny ufw policy के साथ बंद करें, केवल 22 और 443 को खुला रखें। nginx के पीछे Ubuntu 24.04 पर certbot का उपयोग करके certificate जारी करें। यदि server पहले से ही कई Compose apps को route करने वाले Traefik के साथ अन्य apps को handle कर रहा है, तो दूसरा proxy install करने के बजाय उस router में mem0 को जोड़ें।
स्मोक टेस्ट: एक मेमोरी जोड़ें और उसे वापस पढ़ें
export MEM0_KEY='<the ADMIN_API_KEY from .env>'
curl -sS -X POST http://127.0.0.1:8888/memories \
-H "Content-Type: application/json" \
-H "X-API-Key: $MEM0_KEY" \
-d '{"messages":[{"role":"user","content":"I deploy with Docker Compose and I run Postgres 17."}],"user_id":"smoke"}'एक सही रिस्पॉन्स एक JSON ऑब्जेक्ट होता है जिसमें results लिस्ट होती है, और प्रत्येक एंट्री में एक id, निकाला गया memory टेक्स्ट, और "event": "ADD" होता है। वर्तमान एल्गोरिदम केवल ADD इवेंट्स लौटाता है। UPDATE और DELETE इवेंट्स को हटा दिया गया था, इसलिए उनकी अनुपस्थिति कोई बग नहीं है।
curl -sS -X POST http://127.0.0.1:8888/search \
-H "Content-Type: application/json" \
-H "X-API-Key: $MEM0_KEY" \
-d '{"query":"which database do I run?","filters":{"user_id":"smoke"},"top_k":5}'Postgres 17 के बारे में तथ्य एक स्कोर के साथ वापस आना चाहिए। जैसा कि दिखाया गया है, आइडेंटिफायर को filters के अंदर पास करें। एक टॉप लेवल user_id अभी भी काम करता है, और जब भी आप इसका उपयोग करते हैं तो सर्वर Top-level user_id in /search is deprecated. Use filters={...} instead. लॉग करता है।
अपने बाद सफाई करें ताकि टेस्ट डेटा वास्तविक सर्च को दूषित न करे:
curl -sS -X DELETE "http://127.0.0.1:8888/memories?user_id=smoke" \
-H "X-API-Key: $MEM0_KEY"यदि सर्च में आपकी अपेक्षा से कम पंक्तियाँ (rows) मिलती हैं, तो रिट्रीवल को दोष देने से पहले डिफॉल्ट्स की जाँच करें। वर्तमान रिलीज में top_k डिफॉल्ट रूप से 20 है, जो पहले 100 था, और threshold डिफॉल्ट रूप से 0.1 है न कि 'none', इसलिए कमजोर मैच अब आपके लिए फिल्टर कर दिए जाते हैं। एक बार जब यह curl पर काम करने लगे, तो यही एंडपॉइंट्स हैं जिन्हें आप एक एजेंट में जोड़ते हैं, चाहे सीधे या उसी VPS पर चल रहे MCP सर्वर के माध्यम से।
बिना किसी OpenAI key के mem0 चलाना
सबसे पहले उस बाधा को देखें, जिसका सामना आप शुरुआती पांच मिनट में ही करेंगे। सर्वर इमेज में provider libraries का एक निश्चित सेट होता है, और /configure उनके बाहर किसी भी चीज़ को अस्वीकार कर देता है:
LLM provider 'ollama' is not bundled in this image. Bundled providers: openai, anthropic, gemini. To use another provider, install its Python package, rebuild the container, and extend BUNDLED_LLM_PROVIDERS in server/main.py.आपको कुछ भी rebuild करने की आवश्यकता नहीं है। Ollama, /v1 पर एक OpenAI-compatible API प्रदान करता है, जो /v1/chat/completions और /v1/embeddings को कवर करता है, और mem0 का openai provider एक openai_base_url स्वीकार करता है। उस key को Ollama की ओर निर्देशित करें और बंडल की गई जाँच सफल हो जाएगी, क्योंकि provider वास्तव में openai है। केवल पता बदलता है।
Ollama को उसी Compose प्रोजेक्ट में जोड़ें:
ollama:
image: ollama/ollama
restart: unless-stopped
networks: [mem0_network]
ports:
- "127.0.0.1:11434:11434"
volumes:
- ollama_models:/root/.ollamaटॉप-लेवल volumes: key के अंतर्गत ollama_models: जोड़ें, फिर एक chat model और एक embedding model pull करें:
docker compose up -d ollama
docker compose exec ollama ollama pull llama3.1:8b
docker compose exec ollama ollama pull nomic-embed-textयदि Ollama पहले से ही host पर systemd unit के रूप में चल रहा है, जैसा कि VPS पर सीधे Ollama चलाना में बताया गया है, तो container को 127.0.0.1:11434 की ओर निर्देशित न करें। mem0 container के अंदर, 127.0.0.1 स्वयं mem0 container है। mem0 service को extra_hosts: ["host.docker.internal:host-gateway"] दें, systemd drop-in में Environment="OLLAMA_HOST=0.0.0.0:11434" सेट करें ताकि Ollama उस पते पर listen करे जिसे bridge access कर सके, और firewall पर 11434 को बंद रखें।
कॉन्फ़िगर करने से पहले मॉडल से उसकी embedding dimension पूछें
यह एक कदम तय करता है कि retrieval काम करेगा या नहीं।
mem0 का pgvector store अपनी table को एक निश्चित vector width, vector vector(1536) के साथ बनाता है, क्योंकि embedding_model_dims डिफ़ॉल्ट रूप से 1536 पर सेट होता है, जो OpenAI के text-embedding-3-small की चौड़ाई है। nomic-embed-text, 768 मान लौटाता है। mem0 के अंदर कोई भी उन दो संख्याओं की तुलना नहीं करता है, इसलिए पहले insert पर Postgres से बेमेल (mismatch) की त्रुटि सामने आती है:
expected 1536 dimensions, not 768इस पैराग्राफ में दी गई संख्या पर भी भरोसा न करें। मॉडल से पूछें:
curl -sS http://127.0.0.1:11434/v1/embeddings \
-H "Content-Type: application/json" \
-d '{"model":"nomic-embed-text","input":"dimension check"}' \
| python3 -c "import json,sys; print(len(json.load(sys.stdin)['data'][0]['embedding']))"यह वह चौड़ाई प्रिंट करता है जिसका उपयोग आपके collection को करना है। कॉन्फ़िगरेशन को एक फ़ाइल में लिखें, क्योंकि shell quoting के माध्यम से Postgres पासवर्ड पेस्ट करने से production में टाइपिंग की गलतियाँ होती हैं।
{
"vector_store": {
"provider": "pgvector",
"config": {
"host": "postgres",
"port": 5432,
"dbname": "postgres",
"user": "postgres",
"password": "<POSTGRES_PASSWORD from .env>",
"collection_name": "memories_local_768",
"embedding_model_dims": 768
}
},
"llm": {
"provider": "openai",
"config": {
"model": "llama3.1:8b",
"api_key": "ollama",
"openai_base_url": "http://ollama:11434/v1",
"temperature": 0.2
}
},
"embedder": {
"provider": "openai",
"config": {
"model": "nomic-embed-text",
"api_key": "ollama",
"openai_base_url": "http://ollama:11434/v1"
}
}
}curl -sS -X POST http://127.0.0.1:8888/configure \
-H "Content-Type: application/json" \
-H "X-API-Key: $MEM0_KEY" \
-d @config.json
curl -sS http://127.0.0.1:8888/configure -H "X-API-Key: $MEM0_KEY"दूसरी कॉल कॉन्फ़िगरेशन को वापस पढ़ती है, जो यह जाँचने का तरीका है कि write सफल रहा। फिर ऊपर दिए गए smoke test को दोहराएं।
उस JSON में चार विवरण स्पष्ट नहीं हैं, और यदि आप उनमें से किसी एक को गलत करते हैं, तो कुछ न कुछ टूट जाएगा।
api_key एक स्ट्रिंग ollama है, और Ollama इसके मान को अनदेखा करता है। यह खाली नहीं हो सकता, क्योंकि जब कोई key सेट नहीं होती है, तो OpenAI client library प्रक्रिया से कोई भी request बाहर जाने से पहले ही error दे देती है। कोई भी गैर-खाली स्ट्रिंग काम करेगी।
embedding_model_dims, vector store पर जाता है, और embedder पर जानबूझकर कोई embedding_dims नहीं है। mem0, OpenAI dimensions पैरामीटर केवल तभी भेजता है जब आप embedding_dims सेट करते हैं, और जो backends Matryoshka truncation लागू नहीं करते हैं, वे उस पैरामीटर को सीधे अस्वीकार कर देते हैं। चौड़ाई वहाँ सेट करें जहाँ table बनाई जाती है, और embedder को वैसे ही छोड़ दें।
collection_name नया है। mem0 अपनी table को CREATE TABLE IF NOT EXISTS के साथ बनाता है, इसलिए मौजूदा collection पर एक अलग चौड़ाई निर्देशित करने से कुछ नहीं होता: पुरानी vector(1536) कॉलम बनी रहती है, और हर insert विफल हो जाता है। चौड़ाई बदलने के लिए एक नए collection नाम की आवश्यकता होती है, या आपको पुरानी table को मैन्युअल रूप से drop करना होगा।
openai_base_url में host, Compose service का नाम ollama है, न कि localhost। Containers अपने साझा नेटवर्क पर service नाम से एक-दूसरे को resolve करते हैं।
पूरी तरह से local path की कीमत
गुणवत्ता के बारे में खुद के प्रति ईमानदार रहें। mem0 के प्रकाशित benchmark स्कोर को frontier models द्वारा extraction करते समय मापा गया था, इसलिए उन्हें अपने VPS पर 8B मॉडल के लिए पूर्वानुमान के बजाय एक सीमा (ceiling) के रूप में मानें। एक छोटा मॉडल अस्पष्ट तथ्य लिखता है, और कभी-कभी JSON मांगे जाने पर prose लौटा देता है, जो एक add कॉल के रूप में दिखाई देता है जो बिना किसी त्रुटि के खाली results सूची लौटाता है।
गति दूसरी कीमत है। केवल CPU पर आधारित extraction में प्रति add कॉल सेकंड लगते हैं, और आप जो भी संदेश स्टोर करते हैं, उसके लिए यह समय खर्च होता है। जो मॉडल मांगे गए JSON से आगे निकलकर बड़बड़ाता है, वह इसे और खराब कर देता है, इसलिए num_predict के साथ उत्तर को सीमित करना किसी भी एक add कॉल के चलने के समय पर एक सीमा लगा देता है। यदि वह latency मायने रखती है, तो GPU वाला VPS ही इसका सही समाधान है। 8B मॉडल पर अधिक CPU cores लगाने से उतनी मदद नहीं मिलती जितनी लोग उम्मीद करते हैं। मशीन बदलने की तुलना में मॉडल बदलना सस्ता विकल्प है, और VPS पर Nemotron 3.5 Lightning आपको pull करने के लिए टैग, आवश्यक RAM, और यह जानकारी देता है कि क्या केवल CPU ही पर्याप्त है।
आप जो भी चुनें, एक नियम लागू होता है: कभी भी एक collection के अंदर embedding models को न मिलाएं। दो अलग-अलग मॉडल जो संयोगवश एक ही चौड़ाई साझा करते हैं, ऐसे vectors उत्पन्न करते हैं जो तुलनीय नहीं होते हैं। Insert सफल हो जाता है, search पंक्तियाँ लौटाता है, और वे पंक्तियाँ गलत होती हैं, जबकि कहीं भी कोई त्रुटि रिपोर्ट नहीं होती है।
Backups: दो डेटाबेस हैं, एक नहीं
सबसे सामान्य mem0 backup गलती केवल एक database का dump लेना है। init-db.sh डिफ़ॉल्ट postgres database के साथ mem0_app बनाता है, और दोनों में अलग-अलग data रहता है। postgres database में pgvector collections रहती हैं, जो memories हैं। mem0_app में users, sessions, API keys और request logs रहते हैं। प्रत्येक self-hosted app अपना state अलग तरीके से विभाजित करता है। इसी कारण एक ही काम करने वाले दो photo servers के लिए भी अलग backup commands चाहिए। इसलिए dump पर भरोसा करने से पहले पढ़ें कि आपका app क्या-क्या store करता है। इस range के दूसरे छोर पर 90s video store के रूप में फिर से बनाई गई Jellyfin library जैसी व्यवस्था होती है। वह अपना पूरा catalogue किसी अन्य service से पढ़ती है। इसलिए उसमें अपनी configuration की copy रखना ही काफी हो सकता है। इसके विपरीत, mem0 के लिए दोनों databases चाहिए। अन्यथा restore बेकार होगा।
यदि आप केवल postgres को रिस्टोर करते हैं, तो मेमोरीज तो वापस आ जाएंगी लेकिन सभी अकाउंट्स और API keys गायब हो जाएंगी, जिससे उन्हें पढ़ने के लिए कोई भी ऑथेंटिकेट नहीं कर पाएगा। दोनों को, साथ ही रोल्स को, एक ही कमांड में डंप करें:
docker compose exec -T postgres pg_dumpall -U postgres --clean \
| gzip > "mem0-$(date +%F).sql.gz"हिस्ट्री वॉल्यूम Postgres से अलग है और इसे अपनी अलग कॉपी की आवश्यकता है:
docker run --rm -v mem0_mem0_history:/data -v "$PWD:/backup" \
alpine tar czf /backup/mem0-history.tgz -C /data .Docker वॉल्यूम नामों के आगे प्रोजेक्ट का नाम जोड़ता है, इसलिए mem0_mem0_history मानने से पहले docker volume ls के साथ अपने वॉल्यूम नाम की पुष्टि करें।
एक स्क्रैच कंटेनर में रिस्टोर करें और किसी भी डेटा पर भरोसा करने से पहले रो काउंट्स (row counts) की जाँच करें:
gunzip -c mem0-2026-08-03.sql.gz \
| docker compose exec -T postgres psql -U postgres -d postgresजिस बैकअप को आपने कभी रिस्टोर नहीं किया, वह केवल एक अनुमान है। एक बार जब डंप सही हो जाएं, तो उन्हें restic snapshots to off-site storage का उपयोग करके सर्वर से बाहर भेज दें, क्योंकि जो बैकअप उसी सर्वर पर रहता है जिसकी वह सुरक्षा कर रहा है, वह वास्तव में किसी चीज की सुरक्षा नहीं करता है।
विफलता के प्रकार और वे सटीक स्ट्रिंग्स जो आपको दिखाई देंगी
{"detail":"Authentication required. Provide a Bearer token or X-API-Key header."} का अर्थ है कि हेडर गायब है या उसकी स्पेलिंग गलत है। नाम X-API-Key है, और curl हेडर नामों को अक्षरशः भेजता है।
{"detail":"At least one identifier (user_id, agent_id, run_id) is required."} किसी add पर आने का मतलब है कि अनुरोध में उनमें से कोई भी नहीं था। एक memory को किसी चीज़ के दायरे में होना चाहिए, क्योंकि search ठीक उन्हीं फ़ील्ड्स पर फ़िल्टर करता है।
LLM provider 'ollama' is not bundled in this image के साथ HTTP 400 का मतलब है कि आपने "provider": "ollama" भेजा है। Ollama की ओर निर्देशित openai_base_url के साथ "provider": "openai" का उपयोग करें।
Postgres से expected 1536 dimensions, not 768 का मतलब है कि collection एक चौड़ाई (width) पर बनाया गया था और embedder दूसरी चौड़ाई लौटा रहा है। vector store पर embedding_model_dims सेट करें और एक नए collection_name का उपयोग करें।
Search ऐसे परिणाम लौटाता है जिनका कोई अर्थ नहीं है मॉडल परिवर्तन के बाद, बिना किसी त्रुटि के। चौड़ाई अभी भी मेल खाती है, इसलिए डेटाबेस ठीक काम कर रहा है, लेकिन दो मॉडल एक ही वाक्य को अलग-अलग स्थितियों में रखते हैं। एक नया collection शुरू करें और फिर से जोड़ें।
Ollama तक पहुँचते समय mem0 लॉग में Connection refused का आमतौर पर मतलब openai_base_url में 127.0.0.1 होता है। कंटेनर के अंदर वह पता स्वयं कंटेनर होता है। service name का उपयोग करें, या जब Ollama host पर चल रहा हो तो host gateway का उपयोग करें।
add पर nginx से 504 Gateway Time-out का मतलब है कि मॉडल ने proxy_read_timeout से अधिक समय लिया। इसे बढ़ाएं, और पुनः प्रयास करने से पहले जांचें कि क्या memory पहले ही लिखी जा चुकी थी।
exit code 137 के दौरान docker compose up --build का मतलब है कि out-of-memory killer डैशबोर्ड बिल्ड को रोक रहा है। swap जोड़ें, या किसी बड़ी मशीन पर image बनाएं और उसे registry में push करें।
error: port 3000 is already in use रिपॉजिटरी के make up टारगेट से आता है, जो 3000 या 8888 पोर्ट के व्यस्त होने पर शुरू होने से इनकार कर देता है। lsof -iTCP:3000 -sTCP:LISTEN के साथ उस पोर्ट के मालिक का पता लगाएं।
FAQ
क्या graph memory के साथ mem0 चलाने के लिए मुझे अभी भी Neo4j की आवश्यकता है?
नहीं। अप्रैल 2026 में जारी किए गए नए memory algorithm ने open source SDK से graph_store और enable_graph configuration keys को हटा दिया है। Entity extraction अब सामान्य add प्रक्रिया के दौरान चलता है और <collection_name>_entities नामक दूसरी pgvector collection में लिखता है, इसलिए अब किसी external graph database, अतिरिक्त container या migration step की आवश्यकता नहीं है। इसका परिणाम यह है कि search results पर relations field अब मौजूद नहीं है। Entities अब memory की ranking को बढ़ाती हैं, न कि आपको traverse करने के लिए edges प्रदान करती हैं, इसलिए जो application उन relationships का उपयोग करती थी, उसे mem0 के बाहर अपने स्वयं के graph store की आवश्यकता होगी।
self-hosted mem0 server चलाने के लिए सबसे छोटा VPS कौन सा है?
यदि language model कहीं और host किया गया है, तो API container, Postgres और dashboard के लिए 2 GB RAM और लगभग 4 GB free disk पर्याप्त है। सबसे कठिन समय पहला build होता है, क्योंकि Next.js dashboard को compile करने में उसे चलाने की तुलना में अधिक memory लगती है, और 1 GB वाले box पर build प्रक्रिया exit code 137 के साथ kill हो जाती है। यदि Ollama उसी server पर चलता है, तो model के लिए अलग से जगह रखें: 4-bit quantisation पर 8B model को अकेले लगभग 6 GB की आवश्यकता होती है, इसलिए 8 GB की योजना बनाएँ।
क्या मैं OpenAI API key के बिना mem0 चला सकता हूँ?
हाँ, Ollama के OpenAI compatible endpoint के माध्यम से। "provider": "ollama" को set करना विफल हो जाता है, क्योंकि server image में केवल openai, anthropic और gemini libraries ही शामिल होती हैं और यह HTTP 400 error देता है। इसके बजाय "provider": "openai" को बनाए रखें और llm तथा embedder दोनों के लिए किसी भी non-empty api_key के साथ "openai_base_url": "http://ollama:11434/v1" को set करें। Ollama इस key को ignore कर देता है, और bundled provider check पास हो जाता है क्योंकि provider वास्तव में openai ही है।
local embedding model पर स्विच करने के बाद mem0 परिणाम क्यों नहीं देता है?
क्योंकि pgvector table एक निश्चित width पर बनाई गई थी। embedding_model_dims डिफ़ॉल्ट रूप से 1536 होता है, nomic-embed-text 768 लौटाता है, और Postgres expected 1536 dimensions, not 768 के साथ insert को अस्वीकार कर देता है। mem0, CREATE TABLE IF NOT EXISTS के साथ table बनाता है, इसलिए केवल संख्या बदलने से मौजूदा collection पर कोई प्रभाव नहीं पड़ता है। embedding_model_dims को अपने model की वास्तविक width पर set करें, /v1/embeddings को call करके और उसके द्वारा लौटाए गए values को गिनकर उस width की पुष्टि करें, और साथ ही vector store को एक नया collection_name दें।