File size: 7,487 Bytes
5ec8557
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b25cc0
 
5ec8557
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b25cc0
 
 
 
 
 
 
 
 
 
 
 
 
 
5ec8557
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f8a7f2f
5ec8557
f8a7f2f
5ec8557
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# 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"]