# Stage 1: Install dependencies (with build tools for native modules) FROM node:22-bookworm-slim AS deps WORKDIR /app RUN apt-get update && apt-get install -y --no-install-recommends \ python3 make g++ \ && rm -rf /var/lib/apt/lists/* COPY package.json package-lock.json ./ RUN npm ci # Stage 2: Build the Next.js application FROM node:22-bookworm-slim AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build # Stage 3: Production image FROM node:22-bookworm-slim AS runner WORKDIR /app # Install ffmpeg for video thumbnail generation RUN apt-get update && apt-get install -y --no-install-recommends \ ffmpeg \ && rm -rf /var/lib/apt/lists/* ENV NODE_ENV=production ENV PORT=3000 # Bind to all interfaces so the container port is reachable ENV HOSTNAME=0.0.0.0 # Store libraries.json in /config so it can be bind-mounted as a directory. # Mounting a directory (not a single file) ensures the atomic rename in # writeLibraries() works — both .tmp and the target are on the same filesystem. ENV LIBRARIES_CONFIG_PATH=/config/libraries.json RUN mkdir -p /config # Copy standalone Next.js output COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/public ./public # Copy native modules — Next.js standalone's file tracer does not follow # .node binary files, so we copy these manually from the deps stage. # Both are listed in serverExternalPackages and resolved at runtime via require(). COPY --from=deps /app/node_modules/better-sqlite3 ./node_modules/better-sqlite3 COPY --from=deps /app/node_modules/sharp ./node_modules/sharp COPY --from=deps /app/node_modules/@img ./node_modules/@img # Create thumbnail cache directory (mounted as a volume in production) RUN mkdir -p /app/.thumbnails EXPOSE 3000 CMD ["node", "server.js"]