# ======================================== # Stage 1: Dependencies # ======================================== FROM node:20-alpine AS deps RUN apk add --no-cache libc6-compat WORKDIR /app # Copy package files COPY package*.json ./ COPY prisma ./prisma/ # Install dependencies RUN npm ci # ======================================== # Stage 2: Builder # ======================================== FROM node:20-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . # Generate Prisma Client RUN npx prisma generate # Build TypeScript RUN npm run build # ======================================== # Stage 3: Runner # ======================================== FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production # Add dumb-init, su-exec and OpenSSL for Prisma RUN apk add --no-cache dumb-init su-exec openssl-dev openssl # Create non-root user RUN addgroup -g 1001 -S nodejs && \ adduser -S nodejs -u 1001 # Copy necessary files - use tsx to run TypeScript directly COPY --from=builder /app/src ./src COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/package*.json ./ # Create uploads directory with proper permissions RUN mkdir -p /app/uploads && \ chown -R nodejs:nodejs /app # Copy entrypoint and set permissions COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh RUN chmod +x /usr/local/bin/docker-entrypoint.sh # Don't switch user here - let entrypoint do it after setting up data dir EXPOSE 13057 # Use dumb-init to handle signals properly # Run as root, entrypoint will switch to nodejs ENTRYPOINT ["dumb-init", "--"] CMD ["docker-entrypoint.sh"]