# syntax=docker/dockerfile:1.7 # ───────────────────────────────────────────────────────────────────────────── # Stage 1: Dependencies (production only) # ───────────────────────────────────────────────────────────────────────────── FROM node:22-bookworm-slim AS deps WORKDIR /app COPY package.json package-lock.json ./ RUN --mount=type=cache,target=/root/.npm \ npm ci --omit=dev --prefer-offline # ───────────────────────────────────────────────────────────────────────────── # Stage 2: Build # ───────────────────────────────────────────────────────────────────────────── FROM node:22-bookworm-slim AS build WORKDIR /app COPY package.json package-lock.json ./ # Force devDependencies: NODE_ENV=production (injected by Coolify as build arg) # would cause npm to skip devDeps, so we explicitly override here. RUN NODE_ENV=development npm ci COPY tsconfig.json tsconfig.build.json ./ COPY src ./src # Copy migration script for compilation COPY scripts/migrate.ts ./scripts/ # Build TypeScript to JavaScript (includes src and scripts/migrate.ts) RUN npm run build # ───────────────────────────────────────────────────────────────────────────── # Stage 3: Runtime # ───────────────────────────────────────────────────────────────────────────── FROM node:22-bookworm-slim AS runtime ENV NODE_ENV=production WORKDIR /app RUN apt-get update && \ apt-get install -y --no-install-recommends \ tini \ ca-certificates \ curl && \ rm -rf /var/lib/apt/lists/* && \ useradd --system --uid 1001 --create-home agenthub COPY --from=deps --chown=agenthub:agenthub /app/node_modules ./node_modules COPY --from=build --chown=agenthub:agenthub /app/dist ./dist COPY --chown=agenthub:agenthub package.json ./ # Copy Drizzle migrations (required for migration runtime) COPY --chown=agenthub:agenthub drizzle ./drizzle COPY --chown=agenthub:agenthub drizzle.config.ts ./ # Copy entrypoint script COPY --chown=agenthub:agenthub scripts/entrypoint.sh /entrypoint.sh # Make entrypoint executable RUN chmod +x /entrypoint.sh USER agenthub EXPOSE 3000 HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \ CMD curl -f http://127.0.0.1:3000/healthz || exit 1 # Use tini as init system for proper signal handling and run entrypoint ENTRYPOINT ["/usr/bin/tini", "--", "/entrypoint.sh"]