# mem0 Self-Hosted - Dockerfile # Multi-stage build for mem0 self-hosted on HF Spaces # Stage 1: Build mem0 API and Dashboard # Stage 2: Runtime with PostgreSQL, supervisord, nginx # ============================================================================= # Stage 1: Build mem0 API (Python) # ============================================================================= FROM python:3.12-slim-bookworm AS api-builder WORKDIR /build/api # Install system dependencies for building RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ git \ curl \ ca-certificates \ && rm -rf /var/lib/apt/lists/* # Copy mem0 server source and root requirements COPY server/ /build/api/ COPY requirements.txt /build/api/requirements.txt # Install Python dependencies RUN pip install --no-cache-dir -r requirements.txt # ============================================================================= # Stage 2: Build Dashboard (Next.js) # ============================================================================= FROM node:20-alpine AS dashboard-builder WORKDIR /build/dashboard # Copy dashboard config files (package.json, next.config, tailwind, etc.) COPY server/dashboard/ /build/dashboard/ # Fetch dashboard source from upstream mem0 repo (sparse clone of src/ and public/) RUN apk add --no-cache git \ && git clone --depth 1 --filter=blob:none --sparse \ https://github.com/mem0ai/mem0.git /tmp/mem0src \ && cd /tmp/mem0src && git sparse-checkout set server/dashboard/src server/dashboard/public \ && rm -rf /build/dashboard/src && cp -r /tmp/mem0src/server/dashboard/src /build/dashboard/src \ && (cp -r /tmp/mem0src/server/dashboard/public /build/dashboard/public 2>/dev/null || mkdir -p /build/dashboard/public) \ && rm -rf /tmp/mem0src # Install dependencies RUN npm install --no-audit --legacy-peer-deps # Build Next.js standalone output - NEXT_PUBLIC_API_URL must be set at build time ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_PUBLIC_API_URL=/api RUN npm run build # NOTE: MEM0_LLM_* and MEM0_EMBEDDER_* are set in the runtime stage below # Fix upstream bug: .env.http://localhost:7860/api is not a valid JS identifier # Affects both server chunks (process.env.) and minified client bundles (s.env.) # Server-side: replace with literal internal API URL # Client-side: restore to NEXT_PUBLIC_API_URL with hardcoded fallback RUN find /build/dashboard/.next -name '*.js' -exec \ sed -i 's|process\.env\.http://localhost:7860/api|"http://localhost:8000"|g' {} + 2>/dev/null || true && \ find /build/dashboard/.next -name '*.js' -exec \ sed -i 's|\.env\.http://localhost:7860/api|.env.NEXT_PUBLIC_API_URL||\"http://localhost:7860/api\"|g' {} + 2>/dev/null || true # NOTE: Do NOT rewrite client PUT/DELETE on /api/auth/refresh to POST. # Upstream contract (correct): PUT stores refresh_token cookie, POST rotates it, # DELETE clears it. nginx routes /api/auth/refresh to the Next.js dashboard # (see nginx.conf), which owns the httpOnly cookie — not to FastAPI.' # ============================================================================= # Stage 3: Runtime - python:3.12-slim-bookworm with PostgreSQL, supervisord, nginx # Pinned to bookworm so glibc matches api-builder exactly # ============================================================================= FROM python:3.12-slim-bookworm SHELL ["/bin/bash", "-c"] # Environment variables ENV PYTHONUNBUFFERED=1 ENV DEBIAN_FRONTEND=noninteractive ENV PGDATA=/data/pgdata ENV PGPORT=5432 # Default LLM/Embedder config — baked in so Space works without manual /api/configure # Override via HF Space Secrets if needed ENV MEM0_LLM_PROVIDER=openai ENV MEM0_LLM_MODEL=memory-hub ENV MEM0_LLM_API_KEY=sk-fc73b173f8a45ee0-e5chee-3b30445a ENV MEM0_LLM_BASE_URL=https://deironk-9router.hf.space/v1 ENV MEM0_LLM_MAX_TOKENS=4000 ENV MEM0_LLM_TEMPERATURE=0.2 ENV MEM0_EMBEDDER_PROVIDER=openai ENV MEM0_EMBEDDER_MODEL=gemini/gemini-embedding-001 ENV MEM0_EMBEDDER_API_KEY=sk-fc73b173f8a45ee0-e5chee-3b30445a ENV MEM0_EMBEDDER_BASE_URL=https://deironk-9router.hf.space/v1 ENV MEM0_EMBEDDER_DIMS=1536 # Add PGDG apt repository for PostgreSQL 15 + pgvector RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates gnupg \ && curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/postgresql.gpg \ && echo "deb [signed-by=/usr/share/keyrings/postgresql.gpg] https://apt.postgresql.org/pub/repos/apt bookworm-pgdg main" \ > /etc/apt/sources.list.d/pgdg.list \ && rm -rf /var/lib/apt/lists/* # Install system dependencies RUN apt-get update && apt-get install -y --no-install-recommends \ # PostgreSQL 15 + pgvector (from PGDG) postgresql-15 \ postgresql-15-pgvector \ postgresql-client-15 \ # Node.js for dashboard runtime nodejs \ npm \ # Process management supervisor \ # Web server nginx \ # Utilities curl \ ca-certificates \ gosu \ procps \ vim \ nano \ htop \ bash \ git \ git-lfs \ gettext-base \ openssh-client \ tar \ gzip \ xz-utils \ bzip2 \ rsync \ && rm -rf /var/lib/apt/lists/* # Create UID 1000 user for HF Spaces FUSE compatibility RUN useradd -u 1000 -m -d /opt/data mem0 && \ mkdir -p /opt/data/{pgdata,sessions,logs,history} && \ chown -R 1000:1000 /opt/data # Copy built API from builder stage (python:3.12-slim base means Python runtime is already present) COPY --from=api-builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages COPY --from=api-builder /usr/local/bin/uvicorn /usr/local/bin/uvicorn COPY --from=api-builder /build/api /opt/mem0/api # Copy built Dashboard from builder stage # dashboard/entrypoint.sh does `cd /app`, so deploy there COPY --from=dashboard-builder /build/dashboard/.next/standalone /app COPY --from=dashboard-builder /build/dashboard/.next/static /app/.next/static COPY --from=dashboard-builder /build/dashboard/public /app/public COPY --from=dashboard-builder /build/dashboard/entrypoint.sh /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh && \ chown -R 1000:1000 /app # Keep /opt/mem0/dashboard as a symlink for compatibility RUN ln -s /app /opt/mem0/dashboard # Copy configuration files COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf COPY nginx.conf /etc/nginx/nginx.conf COPY nginx-proxy.conf /etc/nginx/proxy.conf COPY entrypoint.sh /entrypoint.sh COPY init-db.sh /init-db.sh COPY postgres-fuse-wrap /usr/local/bin/postgres-fuse-wrap RUN chmod +x /entrypoint.sh /init-db.sh /usr/local/bin/postgres-fuse-wrap # Create runtime directories writable by mem0 (UID 1000) RUN mkdir -p /var/log/nginx /var/cache/nginx /run/nginx \ /var/log/supervisor /run/supervisor /var/run/postgresql \ /var/lib/nginx/body /var/lib/nginx/fastcgi \ /var/lib/nginx/proxy /var/lib/nginx/scgi /var/lib/nginx/uwsgi \ /app && \ chown -R 1000:1000 /var/log/nginx /var/cache/nginx /run/nginx \ /var/log/supervisor /run/supervisor /var/run/postgresql \ /var/lib/nginx # Expose HF Spaces port EXPOSE 7860 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \ CMD curl -f http://localhost:7860/health || exit 1 # Run as root for initialization, then drop to UID 1000 ENTRYPOINT ["/entrypoint.sh"]