# Stage 1: Base Image FROM node:20-alpine AS base RUN apk add --no-cache libc6-compat WORKDIR /app # Stage 2: Dependencies FROM base AS deps COPY package.json package-lock.json* ./ RUN npm ci # Stage 3: Builder FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . ENV NEXT_TELEMETRY_DISABLED=1 ENV NODE_ENV=production ARG NEXT_PUBLIC_APP_URL=http://localhost:3000 ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL # Umami Analytics - build-time (NEXT_PUBLIC_* is inlined by the compiler, and # next.config.ts also reads NEXT_PUBLIC_UMAMI_SRC to widen the CSP) ARG NEXT_PUBLIC_UMAMI_SRC="" ARG NEXT_PUBLIC_UMAMI_ID="" ENV NEXT_PUBLIC_UMAMI_SRC=$NEXT_PUBLIC_UMAMI_SRC ENV NEXT_PUBLIC_UMAMI_ID=$NEXT_PUBLIC_UMAMI_ID RUN npm run build # Stage 4: Production Runner FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1 ENV PORT=3000 ENV HOSTNAME="0.0.0.0" RUN apk add --no-cache libc6-compat # Docker CLI: lets the admin dashboard's "Docker Logs" page # (src/app/api/admin/logs/stream) run `docker logs -f` against the host's # Docker daemon for the app/postgres containers. Only useful if # /var/run/docker.sock is bind-mounted in (see docker-compose.yml) — without # the mount this binary is inert. su-exec is for docker-entrypoint-logs.sh's # privilege drop, see below. RUN apk add --no-cache docker-cli su-exec # Security: Non-root user for the actual app process. The container itself # still starts as root (no USER here) so docker-entrypoint-logs.sh can fix up # /var/run/docker.sock permissions before dropping to nextjs — see that # script for why. This is equivalent to root-level access to the Docker # daemon (and thus the host) for anything that can execute code as nextjs; # accepted trade-off for the live log viewer, see docker-compose.yml. RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs COPY --from=builder /app/public ./public # Set correct permissions for prerender cache RUN mkdir .next RUN chown nextjs:nodejs .next # Copy standalone build and static files COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static COPY docker-entrypoint-logs.sh /usr/local/bin/docker-entrypoint-logs.sh RUN chmod +x /usr/local/bin/docker-entrypoint-logs.sh EXPOSE 3000 ENTRYPOINT ["/usr/local/bin/docker-entrypoint-logs.sh"] CMD ["node", "server.js"]