# syntax=docker/dockerfile:1 # Multi-stage build for the SPA: node build → nginx serve. FROM node:20-alpine AS build WORKDIR /app COPY frontend/package*.json ./ RUN npm ci COPY frontend/ ./ RUN npm run build # Unprivileged nginx: runs as uid 101, listens on 8080, writes only to /tmp — # works under the chart's runAsNonRoot + readOnlyRootFilesystem + drop-ALL-caps # hardening (plain nginx:alpine runs as root and can't bind :80 there). FROM nginxinc/nginx-unprivileged:1.27-alpine AS serve # CVE patches: switch to root just for apk, then back to the non-root user. USER root RUN apk upgrade --no-cache COPY --from=build /app/dist /usr/share/nginx/html # Template (not conf.d): nginx entrypoint runs envsubst → conf.d/default.conf at # start, injecting ${BACKEND_UPSTREAM} from the deployment env. COPY deploy/nginx/default.conf.template /etc/nginx/templates/default.conf.template USER 101 EXPOSE 8080