# ---- build ------------------------------------------------------------------ # Debian rather than Alpine on purpose. The PWA icon generator pulls in sharp, # whose native dependencies differ between glibc and musl, so a lockfile # committed from a glibc machine can never satisfy `npm ci` on Alpine. This # stage is discarded, so its size does not reach the published image. FROM node:24-slim AS build WORKDIR /app # Dependencies first, so a source-only change does not re-install them. COPY package.json package-lock.json ./ RUN npm ci COPY . . RUN npm run build # ---- serve ------------------------------------------------------------------ # Caddy rather than nginx: the app needs a secure context for its service worker, # and Caddy obtains and renews the certificate on its own. FROM caddy:2-alpine COPY docker/Caddyfile /etc/caddy/Caddyfile COPY --from=build /app/dist /srv EXPOSE 80 443 HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \ CMD wget -qO- http://127.0.0.1:8080/healthz || exit 1