# Production Dockerfile for Maternal Web (Next.js 15) # Multi-stage build for security and optimization # Stage 1: Dependencies FROM node:20-alpine AS deps RUN apk add --no-cache libc6-compat WORKDIR /app # Copy package files COPY package*.json ./ RUN npm ci --only=production # Stage 2: Builder FROM node:20-alpine AS builder WORKDIR /app # Copy dependencies from deps stage COPY --from=deps /app/node_modules ./node_modules COPY package*.json ./ COPY tsconfig*.json ./ COPY next.config.js ./ # Copy source code COPY app/ ./app/ COPY components/ ./components/ COPY contexts/ ./contexts/ COPY hooks/ ./hooks/ COPY lib/ ./lib/ COPY locales/ ./locales/ COPY public/ ./public/ COPY styles/ ./styles/ COPY types/ ./types/ # Set build-time environment variables ARG NEXT_PUBLIC_API_URL ARG NEXT_PUBLIC_GRAPHQL_URL ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} ENV NEXT_PUBLIC_GRAPHQL_URL=${NEXT_PUBLIC_GRAPHQL_URL} # Build the application RUN npm run build # Stage 3: Production Runner FROM node:20-alpine AS runner WORKDIR /app # Install dumb-init for proper signal handling RUN apk add --no-cache dumb-init # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nextjs -u 1001 # Set production environment ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 # Copy necessary files from builder COPY --from=builder --chown=nextjs:nodejs /app/next.config.js ./ COPY --from=builder --chown=nextjs:nodejs /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static # Copy locales for i18n COPY --from=builder --chown=nextjs:nodejs /app/locales ./locales # Switch to non-root user USER nextjs # Expose port (default 3000, configurable via PORT env var) EXPOSE 3000 # Health check HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD node -e "require('http').get('http://localhost:' + (process.env.PORT || 3000) + '/api/health', (r) => {r.statusCode === 200 ? process.exit(0) : process.exit(1)})" # Use dumb-init to handle signals properly ENTRYPOINT ["dumb-init", "--"] # Start Next.js using the standalone server CMD ["node", "server.js"]