# ────────────────────────────────────────────────────────────────────────────── # Stage 1 — dependency builder # Compiles packages that need build-essential (e.g. insightface C extensions). # Keeps the final image lean by not shipping compilers to production. # ────────────────────────────────────────────────────────────────────────────── FROM python:3.11-slim AS builder WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libglib2.0-0 \ libgl1 \ libgomp1 \ && rm -rf /var/lib/apt/lists/* COPY requirements.txt . # Install into /install so we can copy just the packages to the final stage RUN pip install --no-cache-dir --prefix=/install -r requirements.txt # ────────────────────────────────────────────────────────────────────────────── # Stage 2 — runtime image (no compilers, smaller attack surface) # ────────────────────────────────────────────────────────────────────────────── FROM python:3.11-slim WORKDIR /app # Runtime system libs only RUN apt-get update && apt-get install -y --no-install-recommends \ libglib2.0-0 \ libgl1 \ libgomp1 \ wget \ && rm -rf /var/lib/apt/lists/* # Copy pre-built Python packages from the builder stage COPY --from=builder /install /usr/local # Copy application source COPY . . # ── PORT fix ────────────────────────────────────────────────────────────────── # NEVER use JSON exec-form with $PORT: # CMD ["uvicorn", "main:app", "--port", "$PORT"] ← shell never runs, $PORT # is passed literally # # Instead, use start.sh which runs in a real shell AFTER Railway injects $PORT. # ───────────────────────────────────────────────────────────────────────────── COPY start.sh /start.sh RUN chmod +x /start.sh EXPOSE 8000 CMD ["/start.sh"]