huggingFlow / Dockerfile
somratpro's picture
fix: 12-point production audit β€” bugs, security, perf, reliability
b6e5beb
# syntax=docker/dockerfile:1
# ════════════════════════════════════════════════════════════════
# HuggingFlow β€” DeerFlow Research Agent for Hugging Face Spaces
# ════════════════════════════════════════════════════════════════
#
# Uses official pre-built DeerFlow images from GHCR β€” no compile step.
# Build time: ~5 min (was 30+ min building from source).
#
# Public port 7860 β†’ health-server.js β†’ nginx:7861 β†’ backend:8001 / frontend:3000
#
# Build args:
# DEERFLOW_BACKEND β€” backend image (default: ghcr.io/bytedance/deer-flow-backend:latest)
# DEERFLOW_FRONTEND β€” frontend image (default: ghcr.io/bytedance/deer-flow-frontend:latest)
# UV_IMAGE β€” uv tool image (default: ghcr.io/astral-sh/uv:0.7.20)
# NODE_MAJOR β€” Node.js major version (default: 22)
ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.7.20
ARG DEERFLOW_BACKEND=ghcr.io/bytedance/deer-flow-backend:latest
ARG DEERFLOW_FRONTEND=ghcr.io/bytedance/deer-flow-frontend:latest
# ── uv source ────────────────────────────────────────────────────
FROM ${UV_IMAGE} AS uv-source
# ── Pre-built DeerFlow images (no source compilation needed) ──────
# Backend image layout: /app/backend/ (Python source + .venv)
# Frontend image layout: /app/frontend/ (built .next + node_modules)
FROM ${DEERFLOW_BACKEND} AS backend-src
FROM ${DEERFLOW_FRONTEND} AS frontend-src
# ── Minimal source clone (skills + config only) ───────────────────
# skills/ and config.example.yaml are not bundled in the official images
FROM alpine/git:latest AS source
RUN git clone --depth=1 \
https://github.com/bytedance/deer-flow.git /src && \
cd /src && \
git log --oneline -1
# ── Runtime ───────────────────────────────────────────────────────
FROM python:3.12-slim-bookworm
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
PYTHONIOENCODING=utf-8 \
PYTHONUNBUFFERED=1
ARG NODE_MAJOR=22
# Layer 1: nginx + base tools (rarely changes β€” stays cached)
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates gnupg nginx openssl \
&& rm -rf /var/lib/apt/lists/*
# Layer 2: Node.js (separate layer β€” apt network stall doesn't force pip re-run)
RUN mkdir -p /etc/apt/keyrings \
&& curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] \
https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \
> /etc/apt/sources.list.d/nodesource.list \
&& apt-get update && apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
# Layer 3: Python helpers with retries (flaky HF Spaces network)
RUN pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 \
huggingface_hub pyyaml \
|| (echo "pip retry 2" && pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 huggingface_hub pyyaml) \
|| (echo "pip retry 3" && pip3 install --no-cache-dir --break-system-packages --timeout 120 --retries 5 huggingface_hub pyyaml) \
|| (echo "ERROR: pip install failed after 3 attempts" && exit 1)
# pnpm for `pnpm start` in Next.js runtime
RUN corepack enable && corepack install -g pnpm@10.26.2
# uv for backend startup (`uv run --no-sync uvicorn ...`)
COPY --from=uv-source /uv /uvx /usr/local/bin/
# ── Create non-root user UID=1000 (required by HF Spaces) ────────
RUN useradd -m -u 1000 -s /bin/bash user && \
mkdir -p \
/app/backend \
/app/frontend \
/app/skills \
/app/data \
/tmp/nginx-tmp && \
chown -R 1000:1000 /app /tmp/nginx-tmp && \
chown -R 1000:1000 /var/log/nginx /var/lib/nginx 2>/dev/null || true
# ── Copy pre-built DeerFlow artifacts ────────────────────────────
# Backend: Python source + pre-built .venv (no uv sync / grpcio compile)
COPY --from=backend-src --chown=1000:1000 /app/backend /app/backend
# Frontend: built .next + node_modules (no pnpm install / Next.js build)
COPY --from=frontend-src --chown=1000:1000 /app/frontend /app/frontend
# Skills (not bundled in official images)
COPY --from=source --chown=1000:1000 /src/skills /app/skills
# Config template
COPY --from=source --chown=1000:1000 /src/config.example.yaml /app/config.example.yaml
# ── Copy HuggingFlow runtime scripts ─────────────────────────────
COPY --chown=1000:1000 nginx.conf /etc/nginx/nginx.conf
COPY --chown=1000:1000 start.sh /app/start.sh
COPY --chown=1000:1000 deerflow-sync.py /app/deerflow-sync.py
COPY --chown=1000:1000 health-server.js /app/health-server.js
COPY --chown=1000:1000 cloudflare-proxy.js /app/cloudflare-proxy.js
COPY --chown=1000:1000 cloudflare-proxy-setup.py /app/cloudflare-proxy-setup.py
COPY --chown=1000:1000 cloudflare-keepalive-setup.py /app/cloudflare-keepalive-setup.py
RUN chmod +x \
/app/start.sh \
/app/deerflow-sync.py \
/app/cloudflare-proxy-setup.py \
/app/cloudflare-keepalive-setup.py
USER user
WORKDIR /app
EXPOSE 7860
# 120s start period β€” restore + backend + frontend startup can take up to 2 min
HEALTHCHECK --interval=30s --timeout=10s --start-period=120s \
CMD curl -fsS http://localhost:7860/health || exit 1
CMD ["/app/start.sh"]