# ============================================ # STAGE 1: BUILDER STAGE # ============================================ # This stage builds the application and prepares assets FROM node:18-alpine AS builder # Set working directory WORKDIR /app # Copy package.json and package-lock.json first (for better caching) COPY package*.json ./ # Copy Prisma schema (needed for Prisma client generation) COPY prisma ./prisma/ # Install ALL dependencies (including dev dependencies for build) RUN npm ci # Copy source code COPY . . # Generate Prisma client RUN npx prisma generate # Build the NestJS application RUN npm run build # Remove development dependencies to reduce size RUN npm prune --production # ============================================ # STAGE 2: PRODUCTION STAGE # ============================================ # This stage creates the final production image FROM node:18-alpine # Install dumb-init for proper signal handling RUN apk add --no-cache dumb-init # Set working directory WORKDIR /app # Create non-root user for security RUN addgroup -g 1001 -S nodejs && \ adduser -S dyolink -u 1001 # Copy package.json files COPY package*.json ./ # Copy Prisma schema COPY prisma ./prisma/ # Install ONLY production dependencies RUN npm ci --only=production && \ npm cache clean --force # Generate Prisma client in production RUN npx prisma generate # Copy built application from builder stage COPY --from=builder /app/dist ./dist # Copy node_modules (already pruned) COPY --from=builder /app/node_modules ./node_modules # Create necessary directories with proper permissions RUN mkdir -p /app/logs && \ chown -R dyolink:nodejs /app # Set ownership of all files to non-root user RUN chown -R dyolink:nodejs /app # Switch to non-root user USER dyolink # Expose the application port EXPOSE 3000 # Health check configuration HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \ CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => {if(r.statusCode!==200)throw new Error()})" || exit 1 # Copy entrypoint script COPY docker-entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/docker-entrypoint.sh # Use dumb-init to properly handle signals ENTRYPOINT ["dumb-init", "--", "docker-entrypoint.sh"] # Start the application CMD ["node", "dist/main"]