# Build stage FROM node:20-alpine AS builder WORKDIR /app # Copy package files first for layer caching COPY package.json package-lock.json* ./ # Install build tools for native modules (better-sqlite3) RUN apk add --no-cache python3 make g++ # Install all dependencies for build RUN npm ci # Copy source files COPY . . # Build the frontend RUN npm run build # Native modules stage — compile better-sqlite3 in a dedicated stage FROM node:20-alpine AS native-deps WORKDIR /app COPY package.json package-lock.json* ./ RUN apk add --no-cache python3 make g++ RUN npm ci --omit=dev # Production stage FROM node:20-alpine AS runner WORKDIR /app # Create non-root user for security (consistent UID/GID 1001) RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 -G nodejs # Set environment ENV NODE_ENV=production ENV SERVER_PORT=3001 ENV RATE_LIMIT_PER_MINUTE=5 ENV CORS_ORIGIN=* ENV LOG_LEVEL=info ENV ZOHO_ENABLED=false ENV ZOHO_API_DOMAIN=https://www.zohoapis.com ENV ZOHO_ACCOUNTS_DOMAIN=https://accounts.zoho.com ENV ZOHO_CLIENT_ID= ENV ZOHO_CLIENT_SECRET= ENV ZOHO_REFRESH_TOKEN= ENV ZOHO_CASES_ENABLED=false # Create app directory structure RUN mkdir -p /app/db /app/logs # Set permissions for db directory (before USER switch) RUN chown -R nodejs:nodejs /app/db /app/logs # Copy from builder - built artifacts and package manifests COPY --from=builder /app/package.json /app/package-lock.json* ./ COPY --from=builder /app/dist ./dist COPY --from=builder /app/server ./server # Copy compiled native modules from native-deps stage (no build tools in final image) COPY --from=native-deps /app/node_modules ./node_modules # Expose backend port EXPOSE 3001 # Switch to non-root user (standard approach, no su-exec needed) USER nodejs # Health check using Node 20 built-in fetch (no wget required) HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ CMD node -e "fetch('http://localhost:3001/api/health').then(r => r.ok ? 0 : 1).catch(() => 1)" || exit 1 # Run the Express server CMD ["node", "server/index.js"]