ARG NODE_IMAGE=mirror.soroushasadi.com/node:20-alpine # --------------------------------------------------------------------------- # 1. Builder — installs deps (including native better-sqlite3 compilation) # then produces the standalone Next.js server bundle. # --------------------------------------------------------------------------- FROM ${NODE_IMAGE} AS builder WORKDIR /app # libc6-compat: needed by Next.js SWC binaries on Alpine. # python3 / make / g++: needed to compile better-sqlite3 native addon. RUN apk add --no-cache libc6-compat python3 make g++ ca-certificates ARG NPM_TOKEN="" COPY package.json package-lock.json .npmrc ./ RUN if [ -n "$NPM_TOKEN" ]; then \ echo "//mirror.soroushasadi.com/repository/npm-group/:_authToken=${NPM_TOKEN}" >> .npmrc ; \ fi \ && npm ci ENV NEXT_TELEMETRY_DISABLED=1 COPY . . RUN npm run build # --------------------------------------------------------------------------- # 2. Runner — minimal image. Standalone server + static assets only. # Content DB + uploads live in /data (mounted volume). # --------------------------------------------------------------------------- FROM ${NODE_IMAGE} AS runner WORKDIR /app RUN apk add --no-cache libc6-compat ca-certificates ENV NODE_ENV=production \ NEXT_TELEMETRY_DISABLED=1 \ PORT=3000 \ HOSTNAME=0.0.0.0 \ DATA_DIR=/data RUN addgroup -g 1001 nodejs && adduser -u 1001 -G nodejs -h /home/nextjs -D nextjs COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/public ./public # Native addon compiled in builder on Alpine/musl — copy explicitly as a # safety net in case file tracing misses the .node binary. COPY --from=builder /app/node_modules/better-sqlite3 ./node_modules/better-sqlite3 COPY --from=builder /app/node_modules/bindings ./node_modules/bindings COPY --from=builder /app/node_modules/file-uri-to-path ./node_modules/file-uri-to-path RUN mkdir -p /data/uploads && chown -R nextjs:nodejs /data /app USER nextjs VOLUME ["/data"] EXPOSE 3000 CMD ["node", "server.js"]