# ── Stage 1: Build React frontend ───────────────────────────────────────────── FROM node:20-alpine AS frontend-builder WORKDIR /app/frontend COPY frontend/package*.json ./ RUN npm install COPY frontend/ . RUN npm run build # ── Stage 2: Python runtime + nginx + supervisord ───────────────────────────── FROM python:3.11-slim # Install nginx, supervisor, and build tools RUN apt-get update && apt-get install -y --no-install-recommends \ nginx \ supervisor \ build-essential \ curl \ && rm -rf /var/lib/apt/lists/* # Install uv RUN pip install --no-cache-dir uv # Copy backend dependency spec (layer cache) WORKDIR /app/backend COPY backend/pyproject.toml . # Install CPU-only torch first (reduces resolver backtracking) RUN uv pip install --system --no-cache \ torch --index-url https://download.pytorch.org/whl/cpu # Install all remaining backend dependencies RUN uv pip install --system --no-cache -e . # Copy full backend source COPY backend/ /app/backend/ # Bake ML models at build time → zero cold-start wait for embedder + reranker RUN python -c "\ from sentence_transformers import SentenceTransformer, CrossEncoder; \ SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2'); \ CrossEncoder('cross-encoder/ms-marco-MiniLM-L-6-v2'); \ print('Models baked into image.')" # Copy React build output from stage 1 COPY --from=frontend-builder /app/frontend/dist /usr/share/nginx/html # nginx + supervisord config COPY nginx.hf.conf /etc/nginx/conf.d/default.conf COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf # HF Spaces runs as non-root (UID 1000); nginx needs writable pid + temp paths RUN sed -i 's|pid /var/run/nginx.pid;|pid /tmp/nginx.pid;|' /etc/nginx/nginx.conf && \ sed -i '/http {/a\ client_body_temp_path /tmp/client_body;\n proxy_temp_path /tmp/proxy;\n fastcgi_temp_path /tmp/fastcgi;' /etc/nginx/nginx.conf && \ mkdir -p /tmp/client_body /tmp/proxy /tmp/fastcgi && \ chown -R 1000:1000 /tmp/client_body /tmp/proxy /tmp/fastcgi /usr/share/nginx/html && \ chown -R 1000:1000 /var/log/nginx /var/lib/nginx || true # Entrypoint script COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # HF Spaces requires port 7860 EXPOSE 7860 CMD ["/entrypoint.sh"]