SSD Nodes Learn 🎉 VPS $4.99/माह से
गाइड Matt Connorलेखक: Matt Connor · अपडेट किया गया: 2026-08-07

VPS पर mem0 को self-host कैसे करें: पूरी गाइड

अपने VPS पर mem0 memory server चलाने का तरीका जानें। इसमें 1 GB RAM की आवश्यकता, Docker Compose सेटअप, TLS कॉन्फ़िगरेशन और Ollama के साथ local integration की पूरी जानकारी दी गई है।

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 -v

docker 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 का सबसे अधिक memory लेने वाला क्षण होता है। 1 GB के VPS पर kernel का out-of-memory killer इसे रोक देता है और build exit code 137 के साथ समाप्त हो जाती है। Docker bug खोजने से पहले कारण की पुष्टि करें:

dmesg -T | grep -i "killed process"

यदि आपको लगता है कि आपकी आवश्यकता के लिए server बहुत अधिक machinery है, तो छोटे विकल्प वास्तविक हैं। बिना server वाला एक local agent memory store और Claude Code के भीतर रहने वाली memory दोनों database का उपयोग नहीं करते हैं। जब कई agents, या कई machines को एक ही memories को पढ़ने की आवश्यकता हो, तब यहाँ वापस आएं।

क्या मुझे mem0 graph memory के लिए Neo4j की आवश्यकता है?

नहीं। यदि कोई गाइड आपको Neo4j container जोड़ने के लिए कहती है, तो वह गाइड कोड से पुरानी है।

mem0 में graph memory का अर्थ पहले एक बाहरी graph database होता था, जिसे graph_store key के अंतर्गत और enable_graph को true पर सेट करके configure किया जाता था। अप्रैल 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 अब उन्हें नहीं रखता है, और आपको mem0 के बाहर अपना स्वयं का graph database रखना होगा, जिसे आपके अपने कोड द्वारा feed किया जाएगा।

रिपॉजिटरी में मौजूद compose file एक development compose है

server/docker-compose.yaml, name: mem0-dev को घोषित करता है, और इसका यही अर्थ है। इसे चलाने से पहले पढ़ें, क्योंकि इसमें मौजूद पाँच चीजें सर्वर के लिए गलत हैं।

  • यह server/dev.Dockerfile से build होता है और .:/app के साथ आपके checkout को image के ऊपर mount करता है, इसलिए container वही चलाता है जो उस directory में मौजूद है, न कि वह जिसे आपने build किया था।
  • इसकी 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 की खपत करता है। Production Dockerfile में भी उसके CMD में --reload होता है, इसलिए आप किसी भी तरह command को override कर देते हैं।
  • प्रकाशित ports "8888:8000", "8432:5432" और "3000:3000" हैं। बिना किसी address के प्रकाशित port 0.0.0.0 पर bind होता है, इसलिए stack शुरू होते ही Postgres 8432 पर public internet को जवाब देने लगता है।

यह अंतिम बिंदु अपनी चेतावनी का हकदार है। Docker, ufw द्वारा प्रबंधित chain से पहले अपने स्वयं के नियम लिखकर port प्रकाशित करता है, इसलिए ufw deny 8432 किसी प्रकाशित container port को बंद नहीं करता है। Docker द्वारा ufw के ऊपर से port प्रकाशित करना इसमें शामिल नियमों के बारे में विस्तार से बताता है।

एक वास्तविक सर्वर के लिए 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 उस तक mem0_network के जरिए service name से पहुँचता है, इसलिए 8432 को publish करने से आपको कुछ नहीं मिलता और एक खुला 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 ले सकता है और उसे move कर सकता है। 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_ value को inline कर देता है, इसलिए इसे बदलने के लिए docker compose up -d --build mem0-dashboard की आवश्यकता होती है। केवल restart करने से पुरानी value 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 .env

POSTGRES_PASSWORD, JWT_SECRET और ADMIN_API_KEY को सेट करें। AUTH_DISABLED=false को वैसे ही रहने दें। यह नाम स्पष्ट है कि वह फ्लैग क्या करता है: यदि यह ऑन है, तो सर्वर अपनी पूरी मेमोरी किसी भी ऐसे व्यक्ति को दे देता है जो उस पोर्ट तक पहुँच सकता है। यदि आप नहीं चाहते कि onboarding event को upstream भेजा जाए, तो MEM0_TELEMETRY=false को सेट करें।

ADMIN_API_KEY की तुलना secrets.compare_digest के साथ X-API-Key हेडर से की जाती है, और मैच होने पर हर database lookup को छोड़ दिया जाता है। यह पूरे API के लिए एक root credential है। इसे उसी तरह संभालें: shell history में न रखें, git में न डालें, और न ही इसे किसी prompt में पेस्ट करें। Compose env files और उनसे secrets कहाँ लीक होते हैं और API keys को agent के context से बाहर रखना दोनों यहाँ सीधे लागू होते हैं, क्योंकि इस सर्वर को कॉल करने वाले agents हैं।

env_file से लोड किए गए मान container environment में रहते हैं, और docker inspect उन्हें पूरा प्रिंट कर देता है। docker group का कोई भी व्यक्ति उन्हें पढ़ सकता है, और docker group का कोई भी व्यक्ति host पर प्रभावी रूप से root होता है।

API के सामने TLS लगाएँ, न कि 8888 पोर्ट खोलें

API 127.0.0.1:8888 पर और डैशबोर्ड 127.0.0.1:3000 पर उत्तर देता है। nginx 443 पर TLS (transport layer security) को समाप्त करता है और दोनों पर ट्रैफिक फॉरवर्ड करता है।

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 जितना दिखता है उससे कहीं अधिक महत्वपूर्ण है। जब language model बातचीत को पढ़ता है और तथ्यों को निकालता है, तब एक add कॉल ब्लॉक हो जाती है। CPU पर चलने वाला एक स्थानीय 8B मॉडल नियमित रूप से nginx के 60 सेकंड के डिफ़ॉल्ट समय से अधिक समय लेता है, और फिर कॉलर को 504 Gateway Time-out दिखाई देता है जबकि मॉडल अभी भी काम कर रहा होता है और मेमोरी अभी भी लिखी जा रही होती है। अंत में आपको एक ऐसी मेमोरी मिलती है जिसके बारे में आपको बताया गया था कि वह विफल हो गई है।

बाकी पोर्ट्स को डिफ़ॉल्ट deny ufw policy के साथ बंद करें, केवल 22 और 443 को खुला रखें। nginx के पीछे Ubuntu 24.04 पर certbot का उपयोग करके सर्टिफिकेट जारी करें। यदि सर्वर पहले से ही कई Compose ऐप्स को रूट करने वाले Traefik के साथ अन्य ऐप्स को होस्ट कर रहा है, तो दूसरा प्रॉक्सी स्थापित करने के बजाय उस राउटर में mem0 को जोड़ें।

Smoke test: एक memory जोड़ें और उसे वापस पढ़ें

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"}'

एक सही response एक JSON object होता है जिसमें results सूची होती है, और प्रत्येक entry में एक id, निकाला गया memory टेक्स्ट, और "event": "ADD" होता है। वर्तमान algorithm केवल ADD events लौटाता है। UPDATE और DELETE events को हटा दिया गया था, इसलिए उनकी अनुपस्थिति कोई bug नहीं है।

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 के बारे में तथ्य एक score के साथ वापस आना चाहिए। जैसा कि दिखाया गया है, identifier को filters के अंदर पास करें। एक top level user_id अभी भी काम करता है, और जब भी आप इसका उपयोग करते हैं तो सर्वर Top-level user_id in /search is deprecated. Use filters={...} instead. log करता है।

अपने बाद सफाई करें ताकि test data वास्तविक searches को दूषित न करे:

curl -sS -X DELETE "http://127.0.0.1:8888/memories?user_id=smoke" \
  -H "X-API-Key: $MEM0_KEY"

यदि search आपकी अपेक्षा से कम rows लौटाती है, तो retrieval को दोष देने से पहले defaults की जाँच करें। वर्तमान release में top_k का default 20 है, जो पहले 100 था, और threshold का default 0.1 है न कि none, इसलिए अब कमजोर matches आपके लिए filter कर दिए जाते हैं। एक बार जब यह curl पर काम करने लगे, तो यही endpoints हैं जिन्हें आप एक agent में जोड़ते हैं, चाहे सीधे या उसी VPS पर चल रहे MCP server के माध्यम से।

बिना किसी OpenAI key के mem0 चलाएं

सबसे पहले उस रुकावट (blocker) पर ध्यान दें, जिसका सामना आपको पहले पांच मिनट में ही करना पड़ेगा। सर्वर इमेज में 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 है। केवल पता (address) बदलता है।

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 के रूप में चल रहा है, जैसा कि running Ollama directly on a VPS में बताया गया है, तो 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 से यह विसंगति सामने आती है:

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 के process से बाहर जाने से पहले ही 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 scores को frontier models के साथ मापा गया था, इसलिए उन्हें अपने VPS पर 8B मॉडल के लिए एक पूर्वानुमान के बजाय एक अधिकतम सीमा (ceiling) के रूप में मानें। एक छोटा मॉडल अस्पष्ट तथ्य लिखता है, और कभी-कभी JSON मांगे जाने पर prose लौटाता है, जो एक add कॉल के रूप में दिखाई देता है जो बिना किसी त्रुटि के एक खाली results सूची लौटाता है।

गति दूसरी लागत है। केवल CPU का उपयोग करके extraction में प्रति add कॉल सेकंड का समय लगता है, और आपके द्वारा स्टोर किया गया प्रत्येक संदेश इसकी कीमत चुकाता है। यदि वह latency मायने रखती है, तो a VPS with a GPU attached ही इसका सही समाधान है। 8B मॉडल पर अधिक CPU cores डालने से लोगों की अपेक्षा से बहुत कम मदद मिलती है।

आप जो भी चुनें, एक नियम लागू होता है: कभी भी एक collection के अंदर embedding models को न मिलाएं। दो अलग-अलग मॉडल जो संयोगवश एक ही चौड़ाई साझा करते हैं, ऐसे vectors उत्पन्न करते हैं जो तुलनीय नहीं होते हैं। Insert सफल हो जाता है, search पंक्तियाँ लौटाता है, और पंक्तियाँ गलत होती हैं, जबकि कहीं भी कोई त्रुटि रिपोर्ट नहीं होती है।

Backups: दो डेटाबेस हैं, एक नहीं

mem0 बैकअप में सबसे आम गलती केवल एक डेटाबेस का डंप लेना है। init-db.sh डिफ़ॉल्ट postgres डेटाबेस के साथ-साथ mem0_app भी बनाता है, और इनमें अलग-अलग डेटा होता है। postgres डेटाबेस में pgvector collections होते हैं, जो कि यादें (memories) हैं। mem0_app में users, sessions, API keys और request logs होते हैं।

यदि आप केवल postgres को रिस्टोर करते हैं, तो यादें तो वापस आ जाएंगी लेकिन सभी accounts और API keys गायब हो जाएंगी, जिससे उन्हें पढ़ने के लिए कोई भी authenticate नहीं कर पाएगा। एक ही कमांड में दोनों, और साथ ही roles का डंप लें:

docker compose exec -T postgres pg_dumpall -U postgres --clean \
  | gzip > "mem0-$(date +%F).sql.gz"

History volume, Postgres से अलग है और इसकी अपनी कॉपी की आवश्यकता है:

docker run --rm -v mem0_mem0_history:/data -v "$PWD:/backup" \
  alpine tar czf /backup/mem0-history.tgz -C /data .

Docker, volume के नामों के आगे project का नाम जोड़ देता है, इसलिए mem0_mem0_history मानने से पहले docker volume ls के साथ अपने volume के नाम की पुष्टि करें।

एक scratch container में रिस्टोर करें और किसी भी चीज़ पर भरोसा करने से पहले row counts की जाँच करें:

gunzip -c mem0-2026-08-03.sql.gz \
  | docker compose exec -T postgres psql -U postgres -d postgres

जिस बैकअप को आपने कभी रिस्टोर नहीं किया, वह केवल एक अनुमान है। एक बार जब डंप सही हो जाएं, तो उन्हें off-site storage पर restic snapshots के माध्यम से सर्वर से बाहर भेज दें, क्योंकि जो बैकअप उसी सर्वर पर रहता है जिसकी वह सुरक्षा कर रहा है, वह वास्तव में किसी चीज़ की सुरक्षा नहीं करता।

विफलता के प्रकार और वे सटीक स्ट्रिंग्स जो आपको दिखाई देंगी

{"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 पर आने का मतलब है कि अनुरोध में उनमें से कोई भी नहीं था। मेमोरी को किसी चीज़ के दायरे में होना चाहिए, क्योंकि सर्च फिल्टर ठीक उन्हीं फ़ील्ड्स पर काम करते हैं।

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 का अर्थ है कि कलेक्शन एक निश्चित चौड़ाई (width) पर बनाया गया था और एम्बेडेड (embedder) कुछ और लौटा रहा है। वेक्टर स्टोर पर embedding_model_dims सेट करें और एक नए collection_name का उपयोग करें।

सर्च द्वारा ऐसी पंक्तियाँ लौटाना जिनका कोई अर्थ नहीं है: मॉडल बदलने के बाद, बिना किसी त्रुटि के। चौड़ाई अभी भी मेल खाती है, इसलिए डेटाबेस सही काम कर रहा है, लेकिन दो मॉडल एक ही वाक्य को अलग-अलग स्थितियों में रखते हैं। एक नया कलेक्शन शुरू करें और फिर से जोड़ें।

Ollama तक पहुँचते समय mem0 लॉग में Connection refused का आमतौर पर मतलब openai_base_url में 127.0.0.1 होता है। कंटेनर के अंदर वह पता कंटेनर ही होता है। सर्विस नाम का उपयोग करें, या जब Ollama होस्ट पर चल रहा हो तो host gateway का उपयोग करें।

add पर nginx से 504 Gateway Time-out का अर्थ है कि मॉडल ने proxy_read_timeout से अधिक समय लिया। इसे बढ़ाएं, और अनुरोध को पुनः प्रयास करने से पहले जांचें कि क्या मेमोरी तब भी लिखी गई थी।

exit code 137 के दौरान docker compose up --build का अर्थ है कि out-of-memory killer डैशबोर्ड बिल्ड को रोक रहा है। स्वैप (swap) जोड़ें, या किसी बड़ी मशीन पर इमेज बिल्ड करें और उसे रजिस्ट्री में पुश करें।

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 अब traverse करने के लिए edges देने के बजाय memory की ranking बढ़ाती हैं, इसलिए जो 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" सेट करने पर यह विफल हो जाता है, क्योंकि server image में केवल openai, anthropic और gemini libraries शामिल हैं और यह HTTP 400 return करता है। इसके बजाय "provider": "openai" को बनाए रखें और llm तथा embedder दोनों के लिए किसी भी non-empty api_key के साथ "openai_base_url": "http://ollama:11434/v1" सेट करें। Ollama key को ignore कर देता है, और bundled provider check पास हो जाता है क्योंकि provider वास्तव में openai ही है।

local embedding model पर स्विच करने के बाद mem0 परिणाम क्यों नहीं देता है?

क्योंकि pgvector table एक निश्चित width पर बनाई गई थी। embedding_model_dims डिफ़ॉल्ट रूप से 1536 है, nomic-embed-text 768 return करता है, और Postgres expected 1536 dimensions, not 768 के साथ insert को अस्वीकार कर देता है। mem0, CREATE TABLE IF NOT EXISTS के साथ table बनाता है, इसलिए केवल संख्या बदलने से मौजूदा collection पर कोई प्रभाव नहीं पड़ता है। embedding_model_dims को अपने model की वास्तविक width पर सेट करें, /v1/embeddings को कॉल करके और उसके द्वारा return किए गए values को गिनकर उस width की पुष्टि करें, और साथ ही vector store को एक नया collection_name दें।