# syntax=docker/dockerfile:1 # Build the React/Vite application first so the runtime image contains only # the compiled frontend and the Python/nginx runtime. FROM node:22-alpine AS frontend-build WORKDIR /frontend COPY frontend/package.json frontend/package-lock.json ./ RUN npm ci --legacy-peer-deps COPY frontend/ ./ RUN npm run build # PyMuPDF embeds TrueType/OpenType fonts, while the browser packages ship # WOFF2 files. Convert the exact browser assets so exported text and typed # signatures use the same glyph metrics as the Fabric preview. FROM python:3.12-slim AS frontend-fonts RUN pip install --no-cache-dir fonttools brotli COPY --from=frontend-build /frontend/node_modules/@fontsource/outfit /fontsource/outfit COPY --from=frontend-build /frontend/node_modules/@fontsource/plus-jakarta-sans /fontsource/plus-jakarta-sans COPY --from=frontend-build /frontend/node_modules/@fontsource/allura /fontsource/allura COPY --from=frontend-build /frontend/node_modules/@fontsource/caveat /fontsource/caveat COPY --from=frontend-build /frontend/node_modules/@fontsource/dancing-script /fontsource/dancing-script COPY --from=frontend-build /frontend/node_modules/@fontsource/great-vibes /fontsource/great-vibes COPY --from=frontend-build /frontend/node_modules/@fontsource/sacramento /fontsource/sacramento COPY scripts/convert_frontend_fonts.py /usr/local/bin/convert-frontend-fonts.py RUN python /usr/local/bin/convert-frontend-fonts.py /fontsource /web-fonts # The runtime image contains both public-facing nginx and the loopback-only # FastAPI/uvicorn process. This keeps deployment to one container while # preserving the existing nginx -> API boundary. FROM python:3.12-slim AS runtime ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONPATH=/app RUN apt-get update \ && apt-get install -y --no-install-recommends \ bash \ fontconfig \ fonts-liberation \ nginx \ && rm -rf /var/lib/apt/lists/* \ && fc-cache -fv \ && rm -f /etc/nginx/sites-enabled/default /etc/nginx/conf.d/default.conf WORKDIR /app # Copy the source tree into /app before installing so the runtime can resolve # the local package (including bundled signature fonts) from PYTHONPATH. COPY backend/pyproject.toml ./ COPY backend/app ./app RUN pip install --no-cache-dir . COPY --from=frontend-build /frontend/dist /usr/share/nginx/html COPY --from=frontend-fonts /web-fonts /app/app/assets/fonts/web COPY frontend/nginx.conf /etc/nginx/conf.d/default.conf COPY docker-entrypoint.sh /usr/local/bin/paperjet-entrypoint RUN chmod +x /usr/local/bin/paperjet-entrypoint \ && nginx -t \ && mkdir -p /data/pdfs /data/thumbnails /data/db EXPOSE 80 HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ CMD ["python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1/api/v1/health', timeout=3)"] ENTRYPOINT ["paperjet-entrypoint"]