# ============================================================ # LambdaAgentPaaS — Multi-stage Dockerfile # # Stage 1 (frontend): Node.js builds the React/Vite webui # Stage 2 (runtime): Python 3.12-slim runs the FastAPI server # with the built frontend baked in # # Data directory: /data (always mount this as a volume) # /data/agentpaas.db SQLite database # /data/instances/ Agent instance data # /data/knowledge_bases/ KB indexes # /data/logs/ Rotating application logs # ============================================================ # ── Stage 1: Build frontend ─────────────────────────────── FROM node:20-alpine AS frontend WORKDIR /build # Copy package files first for layer caching COPY webui/package.json webui/package-lock.json* webui/ RUN cd webui && npm ci --prefer-offline # Copy full webui source COPY webui/ webui/ # Build — vite.config.ts outputs to ../webui-dist (= /build/webui-dist) RUN cd webui && npm run build # ── Stage 2: Python runtime ────────────────────────────── FROM python:3.12-slim AS runtime WORKDIR /app # System dependencies (for PDF processing if used) RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ && rm -rf /var/lib/apt/lists/* # Copy Python package manifests first (cache layer) COPY lambdagent/pyproject.toml lambdagent/ COPY lambdagent_guard/pyproject.toml lambdagent_guard/ COPY agentpaas/pyproject.toml agentpaas/ # Install dependencies before copying full source (better caching) COPY lambdagent/ lambdagent/ COPY lambdagent_guard/ lambdagent_guard/ COPY agentpaas/ agentpaas/ # Install Python packages # Use PyPI mirror configurable via build arg (for Chinese networks) ARG PIP_INDEX_URL=https://pypi.org/simple RUN pip install --no-cache-dir \ -i ${PIP_INDEX_URL} \ -e "lambdagent[all]" \ -e "lambdagent_guard" \ -e "agentpaas[all]" \ pymupdf # Copy built frontend from Stage 1 COPY --from=frontend /build/webui-dist /app/webui-dist # ── Runtime config ──────────────────────────────────────── # All user data lives under /data — mount this as a volume ENV AGENTPAAS_DATA_DIR=/data ENV AGENTPAAS_HOST=0.0.0.0 ENV AGENTPAAS_PORT=8000 # /data is the single volume mount point for all persistent state VOLUME ["/data"] EXPOSE 8000 # audit/AUDIT_2026-06-05.md #32: run as a non-root user. The container's # default UID would otherwise be 0; any RCE in the python process (or a # malicious agent template / pickle deserialization elsewhere) would get # root inside the container. UID 10001 dodges collision with common # host-mapped UIDs (0-9999 are typically already taken by host users). # /data and /app are chown'd so the runtime can still write logs + # instance state to the volume mount. RUN useradd --create-home --uid 10001 --shell /usr/sbin/nologin appuser \ && mkdir -p /data \ && chown -R appuser:appuser /data /app USER appuser HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -sf http://localhost:8000/health || exit 1 CMD ["python", "-m", "agentpaas", "serve", "--host", "0.0.0.0", "--port", "8000"]