Spaces:
Paused
Paused
File size: 5,642 Bytes
bd0c393 687c673 bd0c393 687c673 bd0c393 | 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 | # ==============================================================================
# Open Notebook - HuggingFace Spaces Dockerfile
# Based on Dockerfile.single, adapted for HuggingFace Spaces constraints:
# - Single container with supervisord
# - Nginx reverse proxy on port 7860 (HF mandatory port)
# - Runs as UID 1000 (HF mandatory user)
# - Persistent storage at /data/
# ==============================================================================
# Stage 1: Frontend Builder
FROM node:20-slim AS frontend-builder
WORKDIR /app/frontend
# Copy dependency files first to leverage cache
COPY frontend/package.json frontend/package-lock.json ./
ARG NPM_REGISTRY=https://registry.npmjs.org/
RUN npm config set registry ${NPM_REGISTRY} \
&& npm config set fetch-retries 5 \
&& npm config set fetch-retry-mintimeout 20000 \
&& npm config set fetch-retry-maxtimeout 120000
# Retry npm ci to survive transient registry ECONNRESETs
RUN i=0; until npm ci; do \
i=$((i+1)); \
if [ "$i" -ge 5 ]; then echo "npm ci failed after $i attempts"; exit 1; fi; \
echo "npm ci failed (attempt $i); retrying in 15s"; sleep 15; \
done
# Copy the rest of the frontend source
COPY frontend/ ./
# Build the frontend
RUN npm run build
# Stage 2: SurrealDB binary (pinned to v2 to match docker-compose.yml)
FROM surrealdb/surrealdb:v2 AS surreal-binary
# Stage 3: Backend Builder
FROM python:3.12-slim-bookworm AS backend-builder
# Install build dependencies
RUN apt-get update && apt-get upgrade -y && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/*
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
WORKDIR /app
# Set build optimization environment variables
ENV UV_HTTP_TIMEOUT=120
# Copy dependency files first
COPY pyproject.toml uv.lock ./
COPY open_notebook/__init__.py ./open_notebook/__init__.py
# Install dependencies
RUN uv sync --frozen --no-dev
# Pre-download tiktoken encoding so the app works offline (issue #264).
ENV TIKTOKEN_CACHE_DIR=/app/tiktoken-cache
RUN mkdir -p /app/tiktoken-cache && \
.venv/bin/python -c "import tiktoken; tiktoken.get_encoding('o200k_base')"
# ==============================================================================
# Stage 4: Runtime (HuggingFace Spaces optimized)
# ==============================================================================
FROM python:3.12-slim-bookworm AS runtime
# Install runtime dependencies (including nginx for reverse proxy)
# All apt installs MUST happen before switching to non-root user
RUN apt-get update && apt-get upgrade -y && apt-get install -y \
ffmpeg \
supervisor \
nginx \
curl \
&& curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get install -y nodejs \
&& rm -rf /var/lib/apt/lists/*
# Install SurrealDB binary (from pinned v2 image)
COPY --from=surreal-binary /surreal /usr/local/bin/surreal
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# ==============================================================================
# HuggingFace Spaces: Create user with UID 1000 (mandatory)
# ==============================================================================
RUN useradd -m -u 1000 user
WORKDIR /app
# Copy backend virtualenv and source code
COPY --from=backend-builder /app/.venv /app/.venv
COPY . /app/
# Copy pre-downloaded tiktoken encoding from builder
COPY --from=backend-builder /app/tiktoken-cache /app/tiktoken-cache
# Copy built frontend from standalone output
COPY --from=frontend-builder /app/frontend/.next/standalone /app/frontend/
COPY --from=frontend-builder /app/frontend/.next/static /app/frontend/.next/static
COPY --from=frontend-builder /app/frontend/public /app/frontend/public
# Bind Next.js to all interfaces
ENV HOSTNAME=0.0.0.0
# Point the app at the pre-baked tiktoken encoding
ENV TIKTOKEN_CACHE_DIR=/app/tiktoken-cache
# ==============================================================================
# Setup directories, Nginx, and permissions for UID 1000
# ==============================================================================
# Copy HuggingFace-specific configuration files
COPY nginx.hf.conf /etc/nginx/nginx.conf
COPY supervisord.hf.conf /etc/supervisor/conf.d/supervisord.conf
COPY start.sh /app/start.sh
RUN chmod +x /app/start.sh
# Ensure wait-for-api script is executable
RUN chmod +x /app/scripts/wait-for-api.sh
# Setup directories with proper permissions for UID 1000
RUN mkdir -p /app/data /data /var/log/supervisor /var/log/nginx \
/var/lib/nginx /var/lib/nginx/body /var/lib/nginx/proxy \
/var/lib/nginx/fastcgi /var/lib/nginx/uwsgi /var/lib/nginx/scgi \
/run /tmp/nginx
# Set ownership for non-root user (UID 1000)
RUN chown -R 1000:1000 /app /data /var/log/supervisor /var/log/nginx \
/var/lib/nginx /run /tmp/nginx /etc/nginx && \
chown -R 1000:1000 /var/run 2>/dev/null || true
# Remove default nginx configs that might conflict
RUN rm -rf /etc/nginx/sites-enabled /etc/nginx/sites-available /etc/nginx/conf.d
# ==============================================================================
# Environment defaults for HuggingFace
# ==============================================================================
ENV SURREAL_URL=ws://localhost:8000/rpc
ENV SURREAL_USER=root
ENV SURREAL_PASSWORD=root
ENV SURREAL_NAMESPACE=open_notebook
ENV SURREAL_DATABASE=open_notebook
ENV OPEN_NOTEBOOK_ENCRYPTION_KEY=change-me-in-hf-secrets
# Switch to non-root user (HF Spaces requirement)
USER user
# Expose HuggingFace's mandatory port
EXPOSE 7860
# Start via our initialization script
CMD ["/app/start.sh"]
|