FROM node:22-alpine AS deps WORKDIR /app COPY package.json package-lock.json* ./ RUN npm ci FROM node:22-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npx prisma generate && npm run build FROM node:22-alpine AS runner WORKDIR /app ENV NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0 # Rootless: feste UID/GID, damit Host-Volumes und Deployments reproduzierbar # dieselbe Identität sehen (kein zufälliges System-UID je nach Build-Reihenfolge). # /data gehört der App, damit SQLite ohne Root-Rechte schreiben kann. RUN addgroup -S -g 10001 app && \ adduser -S -u 10001 -G app app && \ mkdir -p /data && chown 10001:10001 /data COPY --from=builder --chown=10001:10001 /app/.next/standalone ./ COPY --from=builder --chown=10001:10001 /app/.next/static ./.next/static COPY --from=builder --chown=10001:10001 /app/prisma ./prisma # Hinweis: Caddyfile und Compose-Dateien gehören zum Deployment, nicht ins Image # (siehe .dockerignore) – das Image enthält nur die App. USER 10001:10001 EXPOSE 3000 # Liveness-Probe gegen den unauthentifizierten /api/health-Endpunkt. HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \ CMD wget -qO- http://127.0.0.1:3000/api/health || exit 1 CMD ["node", "server.js"]