32 lines
1.3 KiB
Docker
32 lines
1.3 KiB
Docker
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"]
|