# ── Dev target ──────────────────────────────────────────────── FROM node:22-slim AS dev WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . EXPOSE 4321 CMD ["npm", "run", "dev"] # ── Prod build stage ───────────────────────────────────────── FROM node:22-slim AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # ── Prod serve stage ───────────────────────────────────────── FROM caddy:2-alpine AS prod # Non-root user RUN addgroup -g 1001 -S app && \ adduser -S app -u 1001 -G app COPY --from=build /app/dist /srv COPY <<'CADDYFILE' /etc/caddy/Caddyfile :8080 { root * /srv file_server encode gzip zstd header { X-Content-Type-Options nosniff X-Frame-Options DENY Referrer-Policy strict-origin-when-cross-origin Cache-Control "public, max-age=31536000, immutable" } handle_errors { rewrite * /404.html file_server } } CADDYFILE RUN chown -R app:app /srv USER app EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD wget -qO- http://127.0.0.1:8080/ || exit 1 CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]