08b6e58b8e
Deploy Vault CMS / deploy (push) Successful in 2m23s
- Upgrade next 16.0.3 -> 16.3.5 and react/react-dom 19.2.0 -> 19.3.0 (CVE-2025-55182 / CVE-2025-66478 unauthenticated RCE), next-auth -> 4.24.15 - Require admin role on /api/users, /api/courses and /api/enrollments, which were unauthenticated - Replace ALLOWED_ADMINS checks that allowed any signed-in user when the variable was empty with the role-based requireAdmin - Sanitize upload filenames, restrict thumbnail extensions, store edited thumbnails in UPLOADS_DIR, tighten traversal checks in file routes - Dockerfile: Node 22, pinned pnpm, non-root user, critical audit gate - Compose: read-only rootfs, dropped caps, no-new-privileges, Postgres password from env - Exclude .env from Docker build context; add security headers - Deploy with git reset --hard instead of git pull - Remove stale package-lock.json Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
62 lines
1.7 KiB
Docker
62 lines
1.7 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 from builder: node_modules and .next build output.
|
|
# 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/node_modules ./node_modules
|
|
COPY --from=builder /app/.next ./.next
|
|
COPY --from=builder /app/public ./public
|
|
COPY --from=builder /app/package.json ./package.json
|
|
RUN mkdir -p .next/cache && chown node:node .next/cache
|
|
|
|
# Set production environment
|
|
ENV NODE_ENV=production
|
|
|
|
# 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 Next.js production server (directly, so npm doesn't need a writable home)
|
|
CMD ["node", "node_modules/next/dist/bin/next", "start"]
|