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 \ && echo "=== post-install check ===" \ && (test -d node_modules/next \ && echo "OK: node_modules/next found: $(cat node_modules/next/package.json | grep '\"version\"' | head -1)" \ || (echo "FATAL: node_modules/next is missing after npm ci" && exit 1)) ENV NEXT_TELEMETRY_DISABLED=1 COPY . . # Diagnose what's in .bin after install, then invoke next directly via node # to bypass any PATH / symlink resolution issues with `npm run`. RUN ls node_modules/.bin/next 2>&1 || echo "WARN: next not in .bin" ; \ node node_modules/next/dist/bin/next 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"]