feat(web-arm): install paperless-ngx #385
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#385
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Design settled in a grilling session on 2026-08-23; the Agent Brief comment below is the contract.
Problem Statement
Household documents (invoices, contracts, tax records, scanned mail) have no searchable, structured archive. They live scattered across mailboxes, scanner output folders and ad-hoc storage, and several people in the household need to keep their documents private from each other.
Solution
Deploy paperless-ngx on web-arm as a native NixOS service, publicly reachable at
paperless.cloonar.com, authenticated via the existing Keycloak SSO with a group gate, with real multi-user separation inside the app. Documents arrive via the web UI/mobile apps and via scan-to-email to a dedicated mailbox; media is stored on a dedicated Hetzner Storage-Box CIFS share; backups combine Storage-Box snapshots, the existing PostgreSQL dumps, and a nightly paperless-native document export picked up by borg.User Stories
scan+<user>@cloonar.comand have the document land in my own archive, so that paper mail is archived without touching a computer.paperlessgroup, so that other realm accounts cannot even authenticate.Implementation Decisions
services.paperless, NixOS 26.05) in a new web-arm host module, imported from the host configuration. No containers.sso.cloonar.com) via paperless's django-allauth support. The OIDC client secret is injected with a sops template so it never enters the Nix store, with a restart trigger on the rendered config hash — the same pattern the Immich module uses. Local password login stays enabled for exactly one break-glass admin account.paperlessconfidential client, a/paperlessgroup carrying apolicy-paperlessrealm role, and a role-gated browser flow mirroring the existing Immich-gated flow, plus the client-secret vault wiring the other clients use.scan@cloonar.commailbox using plus-addressing (scan+alice@), with per-user mail rules and owner-assigning workflows configured later in the UI. The consume directory stays local-only for admin bulk imports over SSH. No network share.nofail, generous mount timeout, ownership forced to the paperless user, andRequiresMountsForon the paperless units. Chosen eyes-open: browsing latency and a hard mount dependency are accepted.postgresqlBackupdumps. Dedicated Redis instance for paperless on a unix socket.document_exporterrun into a local directory that the existing borg/varpaths already cover.deu+eng; PDFs/images only — no Tika/Gotenberg.paperless.cloonar.comwith ACME via the existing lego setup;PAPERLESS_URLset to the exact external URL for CSRF.Testing Decisions
This repo has no unit tests; the gate is the pre-commit hook's dry-build of affected hosts (
scripts/test-configurationvia the installed hook — commit and let the hook run it, don't invoke it manually). Runtime verification happens after deploy by the maintainer.Out of Scope
scan@cloonar.commailbox on the mail host, the DNS record forpaperless.cloonar.com, and the Storage-Box sub-account + snapshot schedule — human actions; the PR must list them.Blocked by
None - can start immediately
Agent Brief
Category: enhancement
Summary: Add paperless-ngx to the web-arm host as a native NixOS service with Keycloak-gated OIDC login, CIFS-backed media storage, and a paperless-native export feeding the existing borg backups.
Current behavior:
web-arm runs nginx (ACME via lego), a shared PostgreSQL 14 with nightly dumps, sops-managed secrets, borg backups of
/varto a Hetzner Storage Box, a declaratively-managed Keycloak realm (sso.cloonar.com), and several native-module services — Immich being the closest precedent (OIDC client secret via sops template, gated Keycloak browser flow, CIFS Storage-Box mount, CPUWeight throttling). There is no document management system.Desired behavior:
https://paperless.cloonar.comserves paperless-ngx. Members of the Keycloak/paperlessgroup log in via SSO; anyone else cannot complete authentication. One local-password admin account remains as break-glass. Uploaded/emailed documents are OCR'd in German and English and stored with the media tree on a dedicated Storage-Box CIFS share; the search index and classifier stay on local disk. A nightlydocument_exporterrun writes a restore-anywhere export into a local directory that the existing borg job already covers.Key interfaces:
services.paperless(NixOS 26.05) — enable; bind to loopback behind nginx; database on the existing shared PostgreSQL 14 instance (socket auth, DB provisioned the way other services on this host do it); a dedicated Redis instance on a unix socket;mediaDiron the CIFS mount, data dir on local disk; settings forPAPERLESS_URL = https://paperless.cloonar.com,PAPERLESS_OCR_LANGUAGE = deu+eng, and OIDC via the allauthPAPERLESS_SOCIALACCOUNT_PROVIDERSmechanism.restartUnits, and add a restart trigger keyed on a hash of the rendered template content (mirror the Immich module's approach).nofail,x-systemd.mount-timeout=2min, credentials from a sops secret, ownership forced to the paperless user/group viauid=/gid=, andRequiresMountsForon every paperless unit that touches media. Do not introduce an automount or idle timeout — that exact construct caused multi-hour Immich outages.paperlessclient (secretfrom the file vault, redirect URI for the allauth OIDC callback on paperless.cloonar.com), a/paperlessgroup carrying apolicy-paperlessrealm role, a role-gated browser flow mirroring the existingbrowser-spnego immichflow family, and the client-secret plumbing the other clients use (theplainClientslist plus aclientSecret-style sops declaration reading the same secret under a second name).paperless.cloonar.comwithenableACME,forceSSL,acmeRoot = null, proxy to loopback with websocket support and a raisedclient_max_body_sizefor large scans.document_exporterinto that local directory, running as the paperless user, off-peak.CPUWeight = 20on the paperless worker/scheduler units and a lowPAPERLESS_TASK_WORKERSso OCR never starves the websites sharing the box.Acceptance criteria:
system.stateVersionuntouched./paperlesscannot complete login, mirroring the Immich gate's structure.nofailand a generous timeout, and stopping the mount stops the paperless services (RequiresMountsFor) — with no automount/idle-timeout anywhere.document_exportertimer writes into a borg-covered local directory.deu+eng; Tika/Gotenberg are absent from the closure.scan@cloonar.commailbox, Keycloak group membership.Out of scope:
*.sops.yamlsecret values (name what's needed in the PR instead).