paperless: port container from Dockerfile to Nix (default.nix)
Wrap nixpkgs paperless-ngx in dockerTools.buildLayeredImage, replacing the s6-overlay Dockerfile build. The package bundles the full OCR/imaging closure (tesseract, qpdf, jbig2enc, unpaper, pngquant, ocrmypdf, pikepdf) and nltk data, so the image stays lean. Unlike the s6 image, this runs as four containers on ringtail sharing one image (web/worker/beat/consumer); the web wrapper mirrors the NixOS module's granian + PYTHONPATH invocation. Self-pins nixos-unstable (stable lags at 2.19.6) for paperless-ngx 2.20.15 -- a same-minor forward patch bump from the v2.20.13 Dockerfile build. Build verified on ringtail (nix-build, exit 0, version assert passes). Also fixes pre-existing shower version drift (service-versions 1.1.2 -> 1.1.3 to match its default.nix) so container-version-check passes; the paperless service-versions edit widens that check to all containers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
944a1570cf
commit
43047423c4
3 changed files with 86 additions and 160 deletions
|
|
@ -1,156 +0,0 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
# Paperless-ngx — self-hosted document management
|
||||
# Built from source via forge mirror of paperless-ngx/paperless-ngx
|
||||
# Closely follows upstream Dockerfile structure with git clone instead of COPY
|
||||
|
||||
ARG CONTAINER_APP_VERSION=v2.20.13
|
||||
|
||||
###############################################
|
||||
# Stage 1: Clone source (reused by later stages)
|
||||
###############################################
|
||||
FROM docker.io/library/alpine:3.22 AS source
|
||||
|
||||
ARG CONTAINER_APP_VERSION
|
||||
RUN apk add --no-cache git
|
||||
RUN git clone --depth 1 --branch ${CONTAINER_APP_VERSION} \
|
||||
https://forge.ops.eblu.me/mirrors/paperless-ngx.git /src
|
||||
|
||||
###############################################
|
||||
# Stage 2: Compile frontend
|
||||
###############################################
|
||||
FROM --platform=$BUILDPLATFORM docker.io/node:20-trixie-slim AS compile-frontend
|
||||
|
||||
COPY --from=source /src/src-ui /src/src-ui
|
||||
WORKDIR /src/src-ui
|
||||
|
||||
RUN set -eux \
|
||||
&& npm update -g pnpm \
|
||||
&& npm install -g corepack@latest \
|
||||
&& corepack enable \
|
||||
&& pnpm install
|
||||
|
||||
RUN set -eux \
|
||||
&& ./node_modules/.bin/ng build --configuration production
|
||||
|
||||
###############################################
|
||||
# Stage 3: s6-overlay base
|
||||
###############################################
|
||||
FROM ghcr.io/astral-sh/uv:0.9.15-python3.12-trixie-slim AS s6-overlay-base
|
||||
|
||||
WORKDIR /usr/src/s6
|
||||
|
||||
ENV S6_BEHAVIOUR_IF_STAGE2_FAILS=2 \
|
||||
S6_CMD_WAIT_FOR_SERVICES_MAXTIME=0 \
|
||||
S6_VERBOSITY=1 \
|
||||
PATH=/command:$PATH
|
||||
|
||||
ARG TARGETARCH
|
||||
ARG TARGETVARIANT
|
||||
ARG S6_OVERLAY_VERSION=3.2.1.0
|
||||
|
||||
RUN set -eux \
|
||||
&& apt-get update \
|
||||
&& apt-get install --yes --quiet --no-install-recommends curl xz-utils \
|
||||
&& S6_ARCH="" \
|
||||
&& if [ "${TARGETARCH}${TARGETVARIANT}" = "amd64" ]; then S6_ARCH="x86_64"; \
|
||||
elif [ "${TARGETARCH}${TARGETVARIANT}" = "arm64" ]; then S6_ARCH="aarch64"; fi \
|
||||
&& if [ -z "${S6_ARCH}" ]; then echo "Error: Cannot determine arch"; exit 1; fi \
|
||||
&& curl --fail --silent --show-error --location --remote-name-all --parallel \
|
||||
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" \
|
||||
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz.sha256" \
|
||||
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" \
|
||||
"https://github.com/just-containers/s6-overlay/releases/download/v${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz.sha256" \
|
||||
&& sha256sum --check ./*.sha256 \
|
||||
&& tar --directory / -Jxpf s6-overlay-noarch.tar.xz \
|
||||
&& tar --directory / -Jxpf s6-overlay-${S6_ARCH}.tar.xz \
|
||||
&& rm ./*.tar.xz ./*.sha256 \
|
||||
&& apt-get --yes purge curl xz-utils \
|
||||
&& apt-get --yes autoremove --purge \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy rootfs (s6 service definitions, init scripts)
|
||||
COPY --from=source /src/docker/rootfs /
|
||||
|
||||
###############################################
|
||||
# Stage 4: Main application
|
||||
###############################################
|
||||
FROM s6-overlay-base AS main-app
|
||||
|
||||
ARG CONTAINER_APP_VERSION
|
||||
ARG DEBIAN_FRONTEND=noninteractive
|
||||
ARG TARGETARCH
|
||||
ARG JBIG2ENC_VERSION=0.30
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONWARNINGS="ignore:::django.http.response:517" \
|
||||
PNGX_CONTAINERIZED=1 \
|
||||
UV_LINK_MODE=copy \
|
||||
UV_CACHE_DIR=/cache/uv/
|
||||
|
||||
# Runtime packages
|
||||
RUN set -eux \
|
||||
&& apt-get update \
|
||||
&& apt-get install --yes --quiet --no-install-recommends \
|
||||
curl gosu tzdata fonts-liberation gettext ghostscript gnupg \
|
||||
icc-profiles-free imagemagick postgresql-client \
|
||||
tesseract-ocr tesseract-ocr-eng tesseract-ocr-deu tesseract-ocr-fra \
|
||||
tesseract-ocr-ita tesseract-ocr-spa unpaper pngquant jbig2dec \
|
||||
libxml2 libxslt1.1 qpdf file libmagic1 media-types zlib1g \
|
||||
libzbar0 poppler-utils \
|
||||
&& curl --fail --silent --show-error --location --remote-name-all \
|
||||
"https://github.com/paperless-ngx/builder/releases/download/jbig2enc-trixie-v${JBIG2ENC_VERSION}/jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb" \
|
||||
&& dpkg --install ./jbig2enc_${JBIG2ENC_VERSION}-1_${TARGETARCH}.deb \
|
||||
&& cp /etc/ImageMagick-6/paperless-policy.xml /etc/ImageMagick-6/policy.xml \
|
||||
&& rm --force *.deb \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /usr/src/paperless/src/
|
||||
|
||||
# Python dependencies
|
||||
COPY --from=source /src/pyproject.toml /src/uv.lock /usr/src/paperless/src/
|
||||
|
||||
RUN --mount=type=cache,target=${UV_CACHE_DIR},id=python-cache \
|
||||
set -eux \
|
||||
&& apt-get update \
|
||||
&& apt-get install --yes --quiet --no-install-recommends \
|
||||
build-essential default-libmysqlclient-dev pkg-config \
|
||||
&& uv export --quiet --no-dev --all-extras --format requirements-txt --output-file requirements.txt \
|
||||
&& uv pip install --system --no-python-downloads --python-preference system --requirements requirements.txt \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" snowball_data \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" stopwords \
|
||||
&& python3 -W ignore::RuntimeWarning -m nltk.downloader -d "/usr/share/nltk_data" punkt_tab \
|
||||
&& apt-get --yes purge build-essential default-libmysqlclient-dev pkg-config \
|
||||
&& apt-get --yes autoremove --purge \
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Copy backend source
|
||||
COPY --from=source /src/src ./
|
||||
|
||||
# Copy compiled frontend
|
||||
COPY --from=compile-frontend /src/src/documents/static/frontend/ ./documents/static/frontend/
|
||||
|
||||
# Create user and finalize
|
||||
RUN set -eux \
|
||||
&& addgroup --gid 1000 paperless \
|
||||
&& useradd --uid 1000 --gid paperless --home-dir /usr/src/paperless paperless \
|
||||
&& mkdir -p /usr/src/paperless/data /usr/src/paperless/media \
|
||||
/usr/src/paperless/consume /usr/src/paperless/export \
|
||||
&& chown -R paperless:paperless /usr/src/paperless \
|
||||
&& s6-setuidgid paperless python3 manage.py collectstatic --clear --no-input --link \
|
||||
&& s6-setuidgid paperless python3 manage.py compilemessages
|
||||
|
||||
VOLUME ["/usr/src/paperless/data", "/usr/src/paperless/media", \
|
||||
"/usr/src/paperless/consume", "/usr/src/paperless/export"]
|
||||
|
||||
ENTRYPOINT ["/init"]
|
||||
EXPOSE 8000
|
||||
|
||||
HEALTHCHECK --interval=30s --timeout=10s --retries=5 \
|
||||
CMD [ "curl", "-fs", "-S", "-L", "--max-time", "2", "http://localhost:8000" ]
|
||||
|
||||
LABEL org.opencontainers.image.title="Paperless-ngx"
|
||||
LABEL org.opencontainers.image.description="Self-hosted document management system"
|
||||
LABEL org.opencontainers.image.version="${CONTAINER_APP_VERSION}"
|
||||
LABEL org.opencontainers.image.source="https://forge.eblu.me/eblume/blumeops"
|
||||
LABEL org.opencontainers.image.vendor="blumeops"
|
||||
77
containers/paperless/default.nix
Normal file
77
containers/paperless/default.nix
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# Nix-built Paperless-ngx for ringtail (amd64).
|
||||
#
|
||||
# Replaces the from-source Dockerfile build (s6-overlay) with nixpkgs'
|
||||
# paperless-ngx, which already bundles the full OCR/imaging closure
|
||||
# (tesseract, ghostscript, imagemagick, qpdf, poppler, jbig2enc) and the
|
||||
# NLTK data via wrappers — so the image stays lean.
|
||||
#
|
||||
# Unlike the upstream s6 image, this image does NOT run all processes
|
||||
# itself. Paperless is multi-process; on ringtail it runs as four
|
||||
# containers sharing this one image, each with a different command:
|
||||
# web -> paperless-web (granian, the wrapper below)
|
||||
# worker -> celery --app paperless worker
|
||||
# beat -> celery --app paperless beat
|
||||
# consumer -> paperless-ngx document_consumer
|
||||
# plus a redis/valkey sidecar. The PYTHONPATH/granian invocation mirrors
|
||||
# the nixpkgs paperless NixOS module's paperless-web service exactly.
|
||||
#
|
||||
# Self-pins nixos-unstable: stable nixpkgs lags at 2.19.6, while unstable
|
||||
# carries 2.20.15 — a same-minor forward patch bump from the previous
|
||||
# Dockerfile build (v2.20.13). The version assertion makes nix-build fail
|
||||
# if a pin bump changes the version, forcing an explicit acknowledgment
|
||||
# here and in service-versions.yaml (enforced by container-version-check).
|
||||
let
|
||||
nixpkgs = fetchTarball {
|
||||
url = "https://github.com/NixOS/nixpkgs/archive/331800de5053fcebacf6813adb5db9c9dca22a0c.tar.gz";
|
||||
sha256 = "1p54fm6dkbq62kpi55cr4wyx7b1nsajpsnjgs64cmp073fwi15f7";
|
||||
};
|
||||
pkgs = import nixpkgs { system = "x86_64-linux"; };
|
||||
|
||||
version = "2.20.15";
|
||||
|
||||
app = pkgs.paperless-ngx;
|
||||
|
||||
# Mirror the NixOS module's paperless-web service: granian serving the
|
||||
# ASGI app with the package's propagated deps + src on PYTHONPATH.
|
||||
pythonPath =
|
||||
"${app.python.pkgs.makePythonPath app.propagatedBuildInputs}:${app}/lib/paperless-ngx/src";
|
||||
|
||||
paperless-web = pkgs.writeShellScriptBin "paperless-web" ''
|
||||
export PYTHONPATH="${pythonPath}"
|
||||
export PAPERLESS_NLTK_DIR="${app.nltkDataDir}"
|
||||
exec ${app.python.pkgs.granian}/bin/granian \
|
||||
--interface asginl --ws \
|
||||
--host 0.0.0.0 --port 8000 \
|
||||
"paperless.asgi:application"
|
||||
'';
|
||||
in
|
||||
|
||||
assert app.version == version;
|
||||
|
||||
pkgs.dockerTools.buildLayeredImage {
|
||||
name = "blumeops/paperless";
|
||||
|
||||
contents = [
|
||||
app
|
||||
paperless-web
|
||||
pkgs.bashInteractive
|
||||
pkgs.coreutils
|
||||
pkgs.cacert
|
||||
pkgs.tzdata
|
||||
];
|
||||
|
||||
config = {
|
||||
# Default command is the web server; worker/beat/consumer containers
|
||||
# override `command` in their k8s manifests.
|
||||
Cmd = [ "${paperless-web}/bin/paperless-web" ];
|
||||
Env = [
|
||||
"PAPERLESS_NLTK_DIR=${app.nltkDataDir}"
|
||||
"SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt"
|
||||
"PYTHONUNBUFFERED=1"
|
||||
"PNGX_CONTAINERIZED=1"
|
||||
];
|
||||
ExposedPorts = {
|
||||
"8000/tcp" = { };
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ services:
|
|||
- name: shower
|
||||
type: argocd
|
||||
last-reviewed: 2026-05-15
|
||||
current-version: "1.1.2"
|
||||
current-version: "1.1.3"
|
||||
upstream-source: https://forge.eblu.me/eblume/adelaide-baby-shower-app
|
||||
notes: |
|
||||
Django app for Adelaide / Heidi / Addie's baby shower. Wheel
|
||||
|
|
@ -339,10 +339,15 @@ services:
|
|||
|
||||
- name: paperless
|
||||
type: argocd
|
||||
last-reviewed: "2026-04-08"
|
||||
current-version: "v2.20.13"
|
||||
last-reviewed: "2026-06-03"
|
||||
current-version: "v2.20.15"
|
||||
upstream-source: https://github.com/paperless-ngx/paperless-ngx/releases
|
||||
notes: Document management; built from source via forge mirror
|
||||
notes: >-
|
||||
Document management. Container ported from Dockerfile to Nix
|
||||
(containers/paperless/default.nix wraps nixpkgs paperless-ngx from a
|
||||
pinned nixos-unstable). Runs as web/worker/beat/consumer containers on
|
||||
ringtail (multi-process; no s6). Bumped v2.20.13 -> v2.20.15 (the
|
||||
unstable package version, same-minor patch) as part of the port.
|
||||
|
||||
- name: unpoller
|
||||
type: argocd
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue