113 lines
5.7 KiB
Markdown
113 lines
5.7 KiB
Markdown
|
|
# 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)
|
|||
|
|
- `6380` → Redis dla workera@SOLARIA (6379 zajęte przez agent-system-redis)
|
|||
|
|
|
|||
|
|
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 rozważyć `PAPERLESS_DISABLE_REGULAR_LOGIN=true`
|
|||
|
|
(TODO DECYZJA OSKARA w compose).
|
|||
|
|
|
|||
|
|
## Storage i backup (WARUNEK BRZEGOWY hybrydy)
|
|||
|
|
|
|||
|
|
Dane na PIHA NVMe:
|
|||
|
|
|
|||
|
|
- `/opt/homelab/data/paperless/media` — **oryginał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ń
|
|||
|
|
|
|||
|
|
### Propozycja backupu (TODO DECYZJA OSKARA — zatwierdzić przed deployem)
|
|||
|
|
|
|||
|
|
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. Alternatywa/uzupełnienie: offsite (restic → chmura?).
|
|||
|
|
VPS odpada (brak miejsca).
|
|||
|
|
3. **Retencja (propozycja)**: 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.
|
|||
|
|
|
|||
|
|
## RAM na PIHA
|
|||
|
|
|
|||
|
|
Oczekiwany spoczynek: paperless ~400–600 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 `paper.kapala.org` → PIHA (DNS Only) + vhost w npm@PIHA (HTTPS → 192.168.31.5:8210).
|
|||
|
|
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).
|