Files
Vault/Dockerfile
T
twotalesanimation ec125261e4
Deploy Vault CMS / deploy (push) Successful in 1m15s
Slim the Docker image and clean up after every deploy
- Build Next.js as a standalone server and copy only that into the
  runtime image, instead of the whole node_modules tree
- Mark three dynamic file reads with turbopackIgnore so the standalone
  trace does not pull in the entire project
- Deploy workflow prunes unused images and build cache older than a day
  at the start and end of every run, including failed ones, and logs
  disk usage before building

Failed builds were leaving their layers behind until the server's disk
filled, which broke the deploy, the database and Gitea sign-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 20:43:34 +02:00

65 lines
1.8 KiB
Docker

# Multi-stage Dockerfile for Next.js CMS
# Stage 1: Build
FROM node:22-alpine AS builder
WORKDIR /app
# Copy package files
COPY package.json pnpm-lock.yaml ./
# Install dependencies (pnpm pinned so builds are reproducible)
RUN npm install -g pnpm@10.22.0 && pnpm install --frozen-lockfile
# Copy source code
COPY . .
# Refuse to build when a production dependency has a known critical
# vulnerability. Runs after COPY so it isn't skipped by the layer cache on
# deploys that only change source code.
RUN pnpm audit --prod --audit-level critical
ARG DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
ENV DATABASE_URL=$DATABASE_URL
# Generate Prisma client
RUN pnpm exec prisma generate
# Build Next.js application
RUN pnpm run build
# Stage 2: Production Runtime
FROM node:22-alpine
WORKDIR /app
# Install dumb-init for proper signal handling
RUN apk add --no-cache dumb-init
# Copy the standalone server (only the files it actually uses, including the
# traced parts of node_modules), plus static assets, which it does not include.
# Files stay root-owned so the app user cannot rewrite its own code; only the
# Next.js cache directory is writable.
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
RUN mkdir -p .next/cache && chown node:node .next/cache
# Set production environment. HOSTNAME makes the server listen on all
# interfaces rather than only the container's hostname.
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
# Run as the unprivileged "node" user (uid 1000) instead of root
USER node
# Expose port 3000
EXPOSE 3000
# Use dumb-init to handle signals properly
ENTRYPOINT ["dumb-init", "--"]
# Start the standalone Next.js server
CMD ["node", "server.js"]