# syntax=docker/dockerfile:1.7 # Base image for building ARG LITELLM_BUILD_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:c61ac6919b811ea53c4782d69f1fe05218ba3c25d53f01b6ab7892e621bd4370 # Runtime image ARG LITELLM_RUNTIME_IMAGE=cgr.dev/chainguard/wolfi-base@sha256:c61ac6919b811ea53c4782d69f1fe05218ba3c25d53f01b6ab7892e621bd4370 ARG UV_IMAGE=ghcr.io/astral-sh/uv:0.11.7@sha256:240fb85ab0f263ef12f492d8476aa3a2e4e1e333f7d67fbdd923d00a506a516a # Pinned by digest like the other base images; bump explicitly on Node upgrades. ARG UI_BUILD_IMAGE=node:20.18-alpine3.20@sha256:3488b10bf958af7125a176419d2d8a9937d895bf124012aae811651988d2ffe6 FROM $UV_IMAGE AS uvbin # Admin UI builder. Pinned to the build platform so the architecture-independent # Next.js static export compiles once natively even in a multi-arch build, # instead of once per target arch under QEMU. FROM --platform=$BUILDPLATFORM $UI_BUILD_IMAGE AS ui-builder ENV NEXT_TELEMETRY_DISABLED=1 \ npm_config_fund=false \ npm_config_audit=false WORKDIR /ui COPY ui/litellm-dashboard/package.json ui/litellm-dashboard/package-lock.json ./ RUN --mount=type=cache,target=/root/.npm npm ci --prefer-offline COPY ui/litellm-dashboard/ ./ RUN npm run build FROM $LITELLM_BUILD_IMAGE AS builder WORKDIR /app USER root COPY --from=uvbin /uv /usr/local/bin/uv COPY --from=uvbin /uvx /usr/local/bin/uvx RUN apk add --no-cache \ bash \ gcc \ python3 \ python3-dev \ openssl \ openssl-dev \ nodejs \ npm \ libsndfile ENV UV_PROJECT_ENVIRONMENT=/app/.venv \ UV_LINK_MODE=copy \ PATH="/app/.venv/bin:${PATH}" # Copy dependency metadata first for layer caching COPY pyproject.toml uv.lock ./ COPY enterprise/pyproject.toml enterprise/ COPY litellm-proxy-extras/pyproject.toml litellm-proxy-extras/ # Install third-party dependencies (cached unless pyproject.toml/uv.lock change) RUN uv sync --frozen --no-install-project --no-install-workspace --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --extra extra_proxy \ --extra semantic-router \ --python python3 # Copy full source tree COPY . . # Replace the committed UI bundle with the one built from this exact source. # Clearing first drops the committed bundle's content-hashed chunks that COPY # would otherwise leave behind alongside the fresh ones. RUN rm -rf litellm/proxy/_experimental/out COPY --from=ui-builder /ui/out/. litellm/proxy/_experimental/out/ # Build Admin UI before final sync (applies the enterprise color override when present) RUN sed -i 's/\r$//' docker/build_admin_ui.sh && chmod +x docker/build_admin_ui.sh && ./docker/build_admin_ui.sh # Install project and workspace packages (fast - deps already cached) RUN uv sync --frozen --no-default-groups --no-editable \ --extra proxy \ --extra proxy-runtime \ --extra extra_proxy \ --extra semantic-router \ --python python3 RUN prisma generate --schema=./schema.prisma RUN sed -i 's/\r$//' docker/entrypoint.sh && chmod +x docker/entrypoint.sh && \ sed -i 's/\r$//' docker/prod_entrypoint.sh && chmod +x docker/prod_entrypoint.sh FROM $LITELLM_RUNTIME_IMAGE AS runtime USER root # node (without npm) is required by the prisma CLI at runtime RUN apk add --no-cache bash openssl tzdata nodejs python3 libsndfile WORKDIR /app ENV PATH="/app/.venv/bin:${PATH}" # Copy only what runtime needs. The application is installed inside the venv; # the rest of the builder's /app is source and build metadata that must not # ship (manifest-scanning tools attribute everything in it to this image). # entrypoint.sh invokes litellm/proxy/prisma_migration.py by source path. COPY --from=builder /app/.venv /app/.venv COPY --from=builder /app/docker /app/docker COPY --from=builder /app/schema.prisma /app/schema.prisma COPY --from=builder /app/litellm/proxy/prisma_migration.py /app/litellm/proxy/prisma_migration.py # enterprise/ is imported by source path at runtime (proxy_cli puts the # working directory on sys.path; litellm/proxy/hooks resolves # enterprise.enterprise_hooks from it) COPY --from=builder /app/enterprise /app/enterprise # Prisma binaries live in $HOME/.cache (default prisma-python location), # which is /root/.cache here. Copy them from the builder so they survive # deployments that volume-mount /app/.cache (e.g. readOnlyRootFilesystem # + emptyDir) — otherwise the mount would shadow the baked-in query engine. # Only the Prisma subdirs: the whole /root/.cache drags in the uv build cache. COPY --from=builder /root/.cache/prisma /root/.cache/prisma COPY --from=builder /root/.cache/prisma-python /root/.cache/prisma-python RUN find /app/.venv -type f -path "*/tornado/test/*" -delete && \ find /app/.venv -type d -path "*/tornado/test" -delete EXPOSE 4000/tcp ENTRYPOINT ["docker/prod_entrypoint.sh"] CMD ["--port", "4000"]