109 lines
4.7 KiB
Docker
109 lines
4.7 KiB
Docker
# syntax=docker/dockerfile:1
|
|||
|
|
#
|
||
|
|
# BentoPDF for bau-pm: BentoPDF built from source at a pinned commit with
|
||
|
|
# BentoPDF's own air-gapped build options, every module it would otherwise load
|
||
|
|
# from a CDN served from this image, and bau-pm's hand-off glue added to every
|
||
|
|
# page. Nothing here edits BentoPDF's code: its documented build arguments, its
|
||
|
|
# runtime config.json, its generated header file with the hosts taken out, and
|
||
|
|
# our files beside its own.
|
||
|
|
#
|
||
|
|
# The images are upstream's: the builder and the runtime stage are the ones
|
||
|
|
# BentoPDF's Dockerfile uses.
|
||
|
|
|
||
|
|
ARG BENTOPDF_REF=v2.8.8
|
||
|
|
ARG BENTOPDF_COMMIT=f96cd4e5166f3d51393dfe9f3c440b5bb77802f1
|
||
|
|
ARG NODE_IMAGE=public.ecr.aws/docker/library/node:20-alpine
|
||
|
|
ARG NGINX_IMAGE=quay.io/nginx/nginx-unprivileged:alpine-slim
|
||
|
|
|
||
|
|
# --- BentoPDF's source, at the commit the tag must point to ---
|
||
|
|
FROM ${NODE_IMAGE} AS source
|
||
|
|
ARG BENTOPDF_REF
|
||
|
|
ARG BENTOPDF_COMMIT
|
||
|
|
RUN apk add --no-cache git
|
||
|
|
RUN git clone --quiet --depth 1 --branch "${BENTOPDF_REF}" https://github.com/alam00000/bentopdf.git /src \
|
||
|
|
&& actual=$(git -C /src rev-parse HEAD) \
|
||
|
|
&& if [ "$actual" != "${BENTOPDF_COMMIT}" ]; then \
|
||
|
|
echo "BentoPDF ${BENTOPDF_REF} is ${actual}, expected ${BENTOPDF_COMMIT}" >&2; exit 1; \
|
||
|
|
fi \
|
||
|
|
&& rm -rf /src/.git
|
||
|
|
|
||
|
|
# --- The CDN modules, packed from npm and checked against vendor.lock ---
|
||
|
|
FROM ${NODE_IMAGE} AS vendor
|
||
|
|
COPY --from=source /src/bentopdf-airgap-bundle /src/bentopdf-airgap-bundle
|
||
|
|
COPY vendor.lock /vendor.lock
|
||
|
|
COPY --chmod=755 scripts/vendor.sh /usr/local/bin/vendor.sh
|
||
|
|
RUN vendor.sh /src /vendor.lock /wasm
|
||
|
|
|
||
|
|
# --- BentoPDF's build, as BentoPDF's Dockerfile runs it ---
|
||
|
|
FROM ${NODE_IMAGE} AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
COPY --from=source /src/package.json /src/package-lock.json ./
|
||
|
|
COPY --from=source /src/vendor ./vendor
|
||
|
|
ENV HUSKY=0
|
||
|
|
RUN npm config set fetch-retries 5 \
|
||
|
|
&& npm config set fetch-retry-mintimeout 60000 \
|
||
|
|
&& npm config set fetch-retry-maxtimeout 300000 \
|
||
|
|
&& npm config set fetch-timeout 600000 \
|
||
|
|
&& npm ci
|
||
|
|
COPY --from=source /src ./
|
||
|
|
|
||
|
|
# The air-gapped build: every module path is this image's own, the CORS proxy
|
||
|
|
# (used only by the X.509 tool, which config.json disables) is switched off,
|
||
|
|
# and Simple Mode drops the marketing pages. Relative paths, so the image does
|
||
|
|
# not know the hostname it will be served under.
|
||
|
|
ENV SIMPLE_MODE=true \
|
||
|
|
DISABLE_GITHUB_STARS=true \
|
||
|
|
COMPRESSION_MODE=all \
|
||
|
|
BASE_URL= \
|
||
|
|
VITE_DEFAULT_LANGUAGE=de \
|
||
|
|
VITE_CORS_PROXY_URL= \
|
||
|
|
VITE_WASM_PYMUPDF_URL=/wasm/pymupdf/ \
|
||
|
|
VITE_WASM_GS_URL=/wasm/gs/ \
|
||
|
|
VITE_WASM_CPDF_URL=/wasm/cpdf/ \
|
||
|
|
VITE_TESSERACT_WORKER_URL=/wasm/ocr/worker.min.js \
|
||
|
|
VITE_TESSERACT_CORE_URL=/wasm/ocr/core \
|
||
|
|
VITE_TESSERACT_LANG_URL=/wasm/ocr/lang-data \
|
||
|
|
VITE_TESSERACT_AVAILABLE_LANGUAGES=deu,fra,ita,eng \
|
||
|
|
VITE_OCR_FONT_BASE_URL=/wasm/ocr/fonts \
|
||
|
|
VITE_EMBEDPDF_FONTS_URL=/wasm/embedpdf \
|
||
|
|
NODE_OPTIONS=--max-old-space-size=3072
|
||
|
|
RUN npm run build
|
||
|
|
|
||
|
|
COPY --chmod=755 scripts/finish.sh /usr/local/bin/finish.sh
|
||
|
|
RUN finish.sh /app
|
||
|
|
|
||
|
|
# --- Upstream's runtime stage, with our files beside BentoPDF's ---
|
||
|
|
FROM ${NGINX_IMAGE}
|
||
|
|
ARG BENTOPDF_REF
|
||
|
|
ARG SOURCE_URL=https://src.bundespruefstelle.ch/magdev/bau-pm-pdf-tools
|
||
|
|
ARG VERSION=dev
|
||
|
|
|
||
|
|
LABEL org.opencontainers.image.title="bau-pm-pdf-tools" \
|
||
|
|
org.opencontainers.image.description="BentoPDF ${BENTOPDF_REF} for bau-pm, without third-party hosts" \
|
||
|
|
org.opencontainers.image.source="${SOURCE_URL}" \
|
||
|
|
org.opencontainers.image.version="${VERSION}" \
|
||
|
|
org.opencontainers.image.licenses="AGPL-3.0-only"
|
||
|
|
|
||
|
|
ENV DISABLE_IPV6=false \
|
||
|
|
PORT=8080
|
||
|
|
|
||
|
|
USER root
|
||
|
|
RUN apk upgrade --no-cache
|
||
|
|
USER nginx
|
||
|
|
|
||
|
|
COPY --chown=nginx:nginx --from=builder /app/dist /usr/share/nginx/html
|
||
|
|
COPY --chown=nginx:nginx --from=builder /app/nginx.conf /etc/nginx/nginx.conf
|
||
|
|
COPY --chown=nginx:nginx --from=builder /app/security-headers.conf /etc/nginx/security-headers.conf
|
||
|
|
COPY --chown=nginx:nginx --from=builder /app/security-headers-docs.conf /etc/nginx/security-headers-docs.conf
|
||
|
|
COPY --chown=nginx:nginx --chmod=755 --from=builder /app/nginx-ipv6.sh /docker-entrypoint.d/99-disable-ipv6.sh
|
||
|
|
COPY --chown=nginx:nginx --chmod=755 --from=builder /app/nginx-noindex.sh /docker-entrypoint.d/98-noindex.sh
|
||
|
|
COPY --chown=nginx:nginx --from=vendor /wasm /usr/share/nginx/html/wasm
|
||
|
|
COPY --chown=nginx:nginx config/config.json /usr/share/nginx/html/config.json
|
||
|
|
COPY --chown=nginx:nginx glue/ /usr/share/nginx/html/bau-pm/
|
||
|
|
RUN sed -i "s#__BAU_PM_SOURCE_URL__#${SOURCE_URL}/src/tag/${VERSION}#" /usr/share/nginx/html/bau-pm/handoff.js \
|
||
|
|
&& grep -q "${SOURCE_URL}" /usr/share/nginx/html/bau-pm/handoff.js \
|
||
|
|
&& mkdir -p /etc/nginx/tmp
|
||
|
|
|
||
|
|
EXPOSE 8080
|
||
|
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 CMD wget --spider -q http://127.0.0.1:8080/ || exit 1
|
||
|
|
CMD ["nginx", "-g", "daemon off;"]
|