# ═══════════════════════════════════════════════════════════════ # MicProtocol — Hugging Face Space (Docker SDK) all-in-one image # Single container running the core stack behind nginx on APP_PORT # (HF maps the public domain to this port). Postgres, Redis, # Meilisearch, mic-realtime, API + BullMQ workers, Web and Admin # all run as processes launched by deploy/start.sh. # NOTE: The full integrations suite (Formbricks, Cal.com, Chatwoot, # Documenso, Listmonk, Umami, Pretix, MinIO, LiveKit, Coturn, Mailhog) # cannot fit in a single free HF cpu-basic container (16 GB RAM). # They are omitted here; deploy them elsewhere if needed. # ═══════════════════════════════════════════════════════════════ # ─── Stage 0: mic-realtime (Erlang/OTP) release ──────────────── # Use Debian-based erlang so the release is glibc-compatible with the # node:20-slim runner (a rebar3 release is self-contained; no Erlang # system packages needed at runtime). FROM erlang:27 AS realtime-build WORKDIR /opt/mic-realtime RUN apt-get update && apt-get install -y --no-install-recommends \ git make g++ openssl libssl-dev curl ca-certificates \ && rm -rf /var/lib/apt/lists/* RUN curl -fsSL -o /usr/local/bin/rebar3 https://s3.amazonaws.com/rebar3/rebar3 \ && chmod +x /usr/local/bin/rebar3 COPY services/mic-realtime/rebar.config ./ RUN rebar3 get-deps || true COPY services/mic-realtime/src ./src COPY services/mic-realtime/config ./config COPY services/mic-realtime/include ./include RUN rebar3 compile && rebar3 release # ─── Stage 1: Python clip-scoring venv ───────────────────────── FROM node:20-slim AS python-build RUN apt-get update && apt-get install -y --no-install-recommends python3 && rm -rf /var/lib/apt/lists/* COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv COPY services/clip-scorer/ /app/services/clip-scorer/ ENV PATH="/opt/venv/bin:$PATH" RUN uv venv --python /usr/bin/python3 /opt/venv \ && VIRTUAL_ENV=/opt/venv uv pip install --index-url https://download.pytorch.org/whl/cpu "torch>=2.0.0" "torchvision>=0.15.0" \ && VIRTUAL_ENV=/opt/venv uv pip install "open-clip-torch>=2.20.0" "transformers>=4.30.0" "Pillow>=10.0.0" "soundfile>=0.12.0" "pyloudnorm>=0.1.0" "numpy>=1.24.0" # ─── Stage 2: Builder (install deps + prisma generate + web + admin builds) ─ # shared-types and api are pre-built locally (nest build needs >4GB heap, # which exceeds HF free-tier container limits). Web and admin build fine on HF. FROM node:20-slim AS builder WORKDIR /app RUN npm install -g pnpm@10.30.3 COPY . . RUN pnpm install --frozen-lockfile # Generate Prisma client (API needs it at runtime) RUN cd apps/api && npx prisma generate # Build Web and Admin on HF (these complete successfully) RUN DOCKER_BUILD=true pnpm --filter @micprotocol/web build RUN DOCKER_BUILD=true pnpm --filter @micprotocol/admin build # Prune to production deps for a smaller runner image RUN CI=true pnpm install --prod --frozen-lockfile # ─── Stage 3: Runner (all-in-one) ────────────────────────────── FROM node:20-slim AS runner WORKDIR /app ENV NODE_ENV=production \ APP_PORT=7860 \ API_PORT=4000 WEB_PORT=3000 ADMIN_PORT=3006 \ MIC_REALTIME_PORT=4001 \ POSTGRES_PORT=5432 REDIS_PORT=6379 MEILISEARCH_PORT=7700 # System services: postgres, redis, nginx, python, tini # (No Erlang packages needed — mic-realtime release is self-contained.) RUN apt-get update && apt-get install -y --no-install-recommends \ postgresql postgresql-contrib redis-server \ ca-certificates curl wget gnupg tini netcat-openbsd python3 \ openssl libpq5 libssl3 \ nginx \ && rm -rf /var/lib/apt/lists/* \ && mkdir -p /var/run/postgresql /var/log/nginx /var/lib/nginx/body # Meilisearch binary COPY --from=getmeili/meilisearch:v1.9.0 /bin/meilisearch /usr/local/bin/meilisearch # mic-realtime release (self-contained, ERTS included) COPY --from=realtime-build /opt/mic-realtime/_build /opt/mic-realtime/_build COPY services/mic-realtime/config /opt/mic-realtime/config # Python venv + clip-scorer source + HF cache COPY --from=python-build --chown=root:root /opt/venv /opt/venv COPY --from=python-build /app/services/clip-scorer /app/services/clip-scorer ENV PATH="/opt/venv/bin:$PATH" HF_HOME=/app/.hf-cache # Built application artifacts from builder COPY --from=builder --chown=root:root /app /app # Restructure Next.js standalone output so start.sh paths work: # standalone puts server.js under apps/web/.next/standalone/apps/web/, # but start.sh expects apps/web/server.js with .next/static and public # alongside it. RUN cp -r apps/web/.next/standalone/apps/web/. apps/web/ \ && cp -r apps/admin/.next/standalone/apps/admin/. apps/admin/ \ && rm -rf apps/web/.next/standalone apps/admin/.next/standalone # Nginx config: single public port -> path-based routing COPY deploy/nginx.conf /etc/nginx/nginx.conf RUN sed -i "s/__APP_PORT__/${APP_PORT}/" /etc/nginx/nginx.conf # Startup script COPY deploy/start.sh /app/start.sh RUN chmod +x /app/start.sh \ && chown -R postgres:postgres /var/run/postgresql /var/lib/postgresql EXPOSE 7860 ENTRYPOINT ["tini", "--"] CMD ["/app/start.sh"]