# Multi-stage build for production FROM node:22-bookworm-slim AS builder RUN apt-get update && apt-get install -y --no-install-recommends \ python3 make g++ git ca-certificates && \ rm -rf /var/lib/apt/lists/* WORKDIR /app # Copy package files COPY package*.json ./ # Install dependencies (including devDependencies for build) RUN npm ci --ignore-scripts # Copy source files COPY . . # Build TypeScript RUN npm run build # Production stage FROM node:22-bookworm-slim # Install dumb-init for proper signal handling RUN apt-get update && apt-get install -y --no-install-recommends dumb-init && \ rm -rf /var/lib/apt/lists/* # Create non-root user RUN groupadd --gid 1001 linkforty && \ useradd --uid 1001 --gid 1001 --create-home --shell /bin/bash linkforty WORKDIR /app # Copy package files COPY package*.json ./ # Install production dependencies only without running package prepare hooks RUN npm ci --omit=dev --ignore-scripts && \ npm cache clean --force # Copy built files from builder COPY --from=builder /app/dist ./dist # Copy example server file COPY examples/basic-server.ts ./ # Install tsx globally for running TypeScript RUN npm install -g tsx # Change ownership to non-root user RUN chown -R linkforty:linkforty /app # Switch to non-root user USER linkforty # Expose port EXPOSE 3000 # Health check HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000/health', (r) => {process.exit(r.statusCode === 200 ? 0 : 1)})" # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] # Run migrations and start server CMD ["sh", "-c", "tsx dist/scripts/migrate.js && tsx basic-server.ts"]