homelab-codex-ws/services/paperless
Oskar Kapala 7e5577c58f feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34
Co zrobione:
- Nextcloud host = PIHA (always-on dla aktywnego uzycia), owner_node +
  LAN_BIND_IP/TRUSTED_PROXIES w .env, README zaktualizowane
- Redis brokera Paperlessa: requirepass, PAPERLESS_REDIS_PASSWORD w .env
  po obu stronach (PIHA + worker@SOLARIA), healthchecki z auth
- Domeny potwierdzone: paper.kapala.org, cloud.kapala.org (Cloudflare
  DNS-only -> Tailscale PIHA, wildcard cert juz pokrywa) — udokumentowane,
  nic nie utworzone
- Backup Paperlessa zatwierdzony: document_exporter + rsync/borg -> SOLARIA,
  retencja 7/4/6, offsite jako future-note
- Nextcloud pin: 34-apache (zweryfikowany aktualny stable, endoflife.date)
- Whoosh fallback-worker: zaakceptowane bez zmian
- Porty/wylaczenie local login/sizing OCR-workera: przeniesione z "decyzji"
  na "TODO przy deployu"
- DECYZJE-do-podjecia.md zaktualizowane: wszystko poza portami/loginem/
  sizingiem przeniesione do "Rozstrzygniete"

Tylko edycja configow w repo — nic nie zdeployowane, zadne kontenery nie
byly ruszane, DNS/vhosty nie utworzone.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-09 16:17:27 +02:00
..
docker-compose.yml feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34 2026-07-09 16:17:27 +02:00
env.example feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34 2026-07-09 16:17:27 +02:00
healthcheck.sh feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34 2026-07-09 16:17:27 +02:00
README.md feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34 2026-07-09 16:17:27 +02:00
service.yaml feat(kb): configi Paperless/Nextcloud wg 9 decyzji — NC na PIHA, domeny kapala, Redis requirepass, backup SOLARIA, NC pin 34 2026-07-09 16:17:27 +02:00

Paperless-ngx (serwis, PIHA)

Serwis dokumentów filaru KB #2 (moduł 2, docs/kb/modules/02-paperless-service.md): UI + API + Postgres + Redis. Always-on na PIHA. Ciężki OCR wykonuje osobny worker na SOLARIA (services/paperless-worker/, moduł 3) — tu zostaje tylko wolny fallback (1 worker × 1 wątek).

Paperless = archiwum REFERENCJA w hybrydzie kb-02 — jego storage jest źródłem prawdy dla KB. Backup jest OBOWIĄZKOWY (patrz niżej), nie opcjonalny.

Stack

Kontener Obraz Rola
paperless ghcr.io/paperless-ngx/paperless-ngx:2.14 UI+API+consumer+fallback-OCR (port 8000)
paperless-db postgres:16-alpine metadane (alias db)
paperless-broker redis:7-alpine (AOF on) kolejka zadań OCR (alias broker)

Wszystkie porty bindowane na LAN_BIND_IP (192.168.31.5), nigdy 0.0.0.0:

  • 8210 → web UI (za npm@PIHA, vhost paper.kapala.org, LAN/Tailscale only)
  • 5434 → Postgres dla workera@SOLARIA (5433 zajęte przez kb-postgres); auth scram
  • 6380 → Redis dla workera@SOLARIA (6379 zajęte przez agent-system-redis); requirepass ustawione — PAPERLESS_REDIS_PASSWORD w .env po obu stronach

Obraz jest multi-arch (arm64 natywnie na Pi 5). Tag 2.14 MUSI być identyczny z services/paperless-worker/docker-compose.yml — podbijać oba naraz.

Split OCR: serwis@PIHA + worker@SOLARIA (wynik badania)

Rozproszony worker nie jest oficjalnie wspierany przez Paperless-ngx, ale jest wykonalny i potwierdzony przez maintainerów (GH discussion #3900): drugi host odpala ten sam obraz z command: celery --app paperless worker i musi widzieć ten sam Redis, tego samego Postgresa i te same pliki. Stąd:

  • storage dokumentów leży na PIHA (bind mounty /opt/homelab/data/paperless/*) i jest eksportowany przez NFS po LAN (nie Tailscale) do SOLARII;
  • ścieżki w kontenerze (/usr/src/paperless/{data,media,consume}) muszą być identyczne po obu stronach — payloady zadań i DB niosą ścieżki absolutne;
  • pliki mają właściciela numerycznego UID 1000 (USERMAP_UID/GID=1000 po obu stronach) — NFS przenosi numeryczne ID, nie nazwy;
  • wbudowany worker na PIHA (nie da się go wyłączyć w stockowym obrazie) działa jako wolny fallback, gdy SOLARIA śpi; zadania czekają w Redis (AOF włączone, restart brokera nie gubi kolejki).

Szczegóły NFS (export na PIHA, mount na SOLARIA, ryzyko indeksu Whoosh) — services/paperless-worker/README.md.

OIDC przez Forgejo

Mechanizm: django-allauth z providerem openid_connect (PAPERLESS_APPS=allauth.socialaccount.providers.openid_connect), konfiguracja providera w JSON-ie PAPERLESS_SOCIALACCOUNT_PROVIDERS (w .env, bo zawiera client secret — patrz env.example).

Rejestracja w Forgejo (Settings → Applications, wzorzec jak Vikunja):

  • Redirect URI: https://paper.kapala.org/accounts/oidc/forgejo/login/callback/
  • Confidential client; scope openid profile email

forgejo.kapala.org jest przypięte przez extra_hosts do 192.168.31.5 (npm na PIHA), żeby OIDC discovery szło po LAN — ta sama lekcja co w Vikunji.

Lokalny login zostaje na czas bootstrapu (konto PAPERLESS_ADMIN_USER); po zweryfikowaniu OIDC ustawić PAPERLESS_DISABLE_REGULAR_LOGIN=true + PAPERLESS_REDIRECT_LOGIN_TO_SSO=true (decyzja podjęta — zrobić PRZY DEPLOYU, po potwierdzeniu logowania OIDC; TODO w compose).

Storage i backup (WARUNEK BRZEGOWY hybrydy)

Dane na PIHA NVMe:

  • /opt/homelab/data/paperless/mediaoryginały + zarchiwizowane PDF-y, niezastępowalne
  • /opt/homelab/data/paperless/data — indeks wyszukiwania (Whoosh) + klasyfikator — odtwarzalne (document_index reindex)
  • /opt/homelab/data/paperless/consume — katalog zrzutu do ingestu
  • paperless_pgdata (named volume) — metadane (tagi, korespondenci, daty)
  • paperless_redisdata (named volume) — AOF kolejki zadań

Backup (zatwierdzone — cel: SOLARIA, LAN; offsite później)

  1. Warstwa 1 — eksport spójny: nocny cron na PIHA: docker exec paperless document_exporter ../export --delete -z — wbudowane narzędzie; zrzuca oryginały + archiwa + manifest.json (pełne metadane, odtwarzalne przez document_importer bez dumpa SQL). Ląduje w /opt/homelab/data/paperless/export.
  2. Warstwa 2 — kopia poza hosta: rsync/borg eksportu na SOLARIA (2 TB NVMe, ta sama LAN) — SOLARIA sesyjna, więc pull przy starcie lub push z retry. Wystarcza na start; VPS odpada (brak miejsca).
  3. Retencja (zatwierdzona): 7 dziennych + 4 tygodniowe + 6 miesięcznych.
  4. Dump Postgresa nie jest konieczny do odtworzenia (manifest wystarcza), ale tani — można dołożyć pg_dump do tej samej nocnej pętli.
  5. Future-note (poza zakresem tego etapu): offsite backup (np. restic → chmura) poza SOLARIA-LAN, gdy pojawi się potrzeba/budżet.

Ten etap to tylko config + dokumentacja decyzji — cron/skrypt deployowy (cron entry na PIHA, rsync/borg do SOLARII) powstaje przy deployu modułu 2, nie tutaj.

RAM na PIHA

Oczekiwany spoczynek: paperless ~400600 Mi (gunicorn + consumer + beat + 1 worker), postgres ~80 Mi, redis ~15 Mi. Limity twarde w hosts/piha/runtime/paperless/docker-compose.override.yml. Warunek: moduł 0 (odchudzenie PIHA) wykonany — po nim ~3.8 Gi available.

Cutover checklist (przy deployu — NIE teraz)

  1. Moduł 0 (piha-slim) domknięty; free -g na PIHA potwierdza zapas.
  2. Porty wolne na żywym hoście: ss -tlnp | grep -E '8210|5434|6380'.
  3. mkdir -p /opt/homelab/data/paperless/{data,media,consume,export} na PIHA.
  4. .env z env.example (sekrety + rejestracja OAuth2 w Forgejo).
  5. DNS: rekord A paper.kapala.org w Cloudflare → 100.108.208.3 (Tailscale PIHA, DNS Only) — ten sam wzorzec co ha.kapala.org / immich.kapala.org (docs/sessions/2026-06-30-kapala-cloudflare-wildcard-mesh.md); wildcard *.kapala.org już pokrywa tę subdomenę, nowy cert niepotrzebny. Plus vhost w npm@PIHA (HTTPS → 192.168.31.5:8210, Advanced puste).
  6. docker compose up -d + ./healthcheck.sh + testowy login OIDC.
  7. Export NFS dla workera (patrz services/paperless-worker/README.md) — dopiero przy module 3.
  8. Wpis w hosts/piha/services.yaml (dopiero przy deployu — wcześniej supervisor widziałby drift dla nieistniejącego serwisu).