FastAPI-UI für KI-Tagging mehrerer Paperless-NGX-Instanzen via lokalem Ollama und n8n. OIDC, verschlüsselte Token, gehärteter Container.
  • Python 54.7%
  • HTML 36.5%
  • CSS 8.6%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Manuel Gläser 4f5c10e1ba README auf das Nötigste gekürzt: nur, was der Wizard nicht abfängt
Installation, Reverse-Proxy, was der OIDC-Provider braucht, Betrieb mit
Update, Sicherung und Login-Fehlersuche. Alles, was die Oberfläche selbst
führt (Anmeldung, Instanz, Modell, Webhook, Benutzer, Ollama-Adresse),
steht nur noch als Ablauf des ersten Starts. Architektur-Interna,
Legacy-API, SQL-Rezepte und die systemd-Skripte sind raus.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-02 20:11:55 +00:00
app ollama: Adresse als Admin-Einstellung in der UI, geprüft und ohne Neustart 2026-10-02 20:05:49 +00:00
.env.example ollama: Adresse als Admin-Einstellung in der UI, geprüft und ohne Neustart 2026-10-02 20:05:49 +00:00
.gitignore Add README + AI-Tool-Verzeichnisse in .gitignore 2026-04-26 15:22:45 +02:00
docker-compose.yml compose: HOST_BIND_IP default 0.0.0.0, Bindungs-Hinweise in README und .env.example 2026-10-02 20:03:05 +00:00
Dockerfile Provider- und Proxy-neutral: README neu, Authentik/NPMplus aus Code und Config 2026-10-02 19:28:20 +00:00
README.md README auf das Nötigste gekürzt: nur, was der Wizard nicht abfängt 2026-10-02 20:11:55 +00:00

paper.ai

KI-Tagging für eine oder mehrere Paperless-NGX-Instanzen mit lokalem Ollama — self-hosted, ohne Cloud. Paperless meldet neue Dokumente per Webhook, paper.ai lässt ein lokales Modell Korrespondent, Dokumenttyp, Tags und Felder vorschlagen und schreibt das Ergebnis zurück, wahlweise automatisch oder zur Durchsicht.

Mehrere Benutzer, jede Paperless-Instanz hat einen Owner, eigenes Modell und eigenen Prompt pro Instanz, Nachbearbeitung bestehender Dokumente, Trace jedes Pipeline-Schritts, Audit-Log. Alles Weitere erklärt die Oberfläche selbst; dieses Dokument beschreibt nur, was vor dem ersten Login passieren muss.

Voraussetzungen

  • Docker mit Compose
  • Ollama, erreichbar vom Container aus. Default ist ein Container ollama im Docker-Netz llm-stuff_llm-network; jede andere Adresse lässt sich später in der Oberfläche eintragen.
  • Ein Reverse-Proxy mit TLS. HTTPS ist Pflicht, das Session-Cookie wird über HTTP nie gesendet.
  • Optional ein OpenID-Connect-Provider. Ohne geht die eingebaute Anmeldung mit Benutzername und Passwort.
  • Eine Paperless-NGX-Instanz mit API-Token

Installation

git clone https://git.glaeser-it.de/klueber-it/paperai.git
cd paperai
cp .env.example .env

mkdir -p secrets data
openssl rand -hex 32 > secrets/config_api_token
openssl rand -hex 32 > secrets/paperless_webhook_token
touch secrets/session_secret secrets/oidc_client_secret
sudo chown -R 1000:1000 secrets data
chmod 600 secrets/*

docker compose build
docker compose up -d

In der .env zählen zum Start zwei Werte:

Variable Bedeutung
HOST_BIND_IP Host-Adresse für Port 8001. Default 0.0.0.0. 127.0.0.1, wenn der Proxy auf demselben Host läuft. Eine feste LAN-IP muss beim Docker-Start schon gebunden sein.
PROXY_TRUSTED_IP Adresse des Reverse-Proxys. Nur von dort werden X-Forwarded-*-Header geglaubt.

Die beiden leeren Secret-Dateien müssen existieren, weil Compose sie erwartet; ihre Werte legt der Wizard in data/oidc.env ab. Wer lieber deklarativ arbeitet, füllt sie und setzt die OIDC_*-Werte in der .env, wie in der .env.example beschrieben.

Heißt dein Ollama-Netz anders, den networks:-Block am Ende von docker-compose.yml anpassen. Ollama als Container ist nicht Pflicht, die Adresse ist später frei wählbar.

Reverse-Proxy

Der Proxy terminiert TLS und leitet an <HOST_BIND_IP>:8001 weiter. Er muss X-Forwarded-For und X-Forwarded-Proto setzen; Caddy tut das von selbst, bei nginx, Traefik und anderen darauf achten.

paperai.example.com {
    reverse_proxy 10.0.0.5:8001
}

Erster Start

https://<dein-host>/ aufrufen. Alles Weitere führt der Wizard:

  1. Anmeldung wählen. OIDC mit Discovery-URL, Client-ID und Client-Secret, oder lokale Anmeldung mit dem ersten Admin-Benutzer. Danach einmal docker compose restart paperless-ai-config.
  2. Erste Paperless-Instanz mit URL und API-Token.
  3. Modell wählen. Ist Ollama nicht erreichbar, zeigt der Schritt die Adresse und den Fehler; ein Admin trägt dort die richtige Adresse ein, sie wird geprüft und gilt sofort. Modelle lassen sich unter „Modelle" ziehen.
  4. Webhook in Paperless einrichten. Der Schritt zeigt URL, Header und Token für die Paperless-Workflow-Aktion; dieselbe Anleitung steht jederzeit unter „System → Webhook".

Der erste angemeldete Benutzer ist Admin. Weitere Benutzer kommen bei OIDC automatisch beim ersten Login, bei lokaler Anmeldung legt sie der Admin unter „System → Benutzer" an.

Was der OIDC-Provider braucht

Der Wizard fragt nur die Werte ab, den Client musst du im Provider anlegen:

Einstellung Wert
Client-Typ Confidential, Authorization-Code-Flow
Redirect-URI https://<dein-host>/auth/callback
Scopes openid email profile
Claims im ID-Token sub (stabil, z.B. User-UUID), preferred_username oder email, optional groups

groups wird nur gebraucht, wenn du den Zugang auf eine Gruppe beschränken oder Admins über eine Gruppe steuern willst (OIDC_REQUIRED_GROUP, OIDC_ADMIN_GROUP). Die Discovery-URL endet auf /.well-known/openid-configuration und steht in der Client-Ansicht des Providers.

Betrieb

Updates. Der Code ist als Bind-Mount eingebunden:

git pull
docker compose up -d --force-recreate

Nur wenn sich das Dockerfile geändert hat, vorher docker compose build --pull. Datenbank-Migrationen laufen beim Start automatisch.

Sichern. data/ (SQLite-Datenbank, Verschlüsselungsschlüssel, oidc.env) und secrets/. Ohne data/.encryption_key sind gespeicherte Paperless-Tokens nicht mehr lesbar.

Fehlersuche beim Login. Fehler stehen im Container-Log (docker compose logs paperless-ai-config).

  • Endlose Weiterleitung: Die Seite läuft über HTTP statt HTTPS, oder das Session-Cookie ist zu groß; das Log warnt ab 3500 Bytes.
  • invalid_grant vom Provider: Ein bereits eingelöster Code wurde erneut geschickt, meist nach einer Weiterleitungsschleife. Die Schleife ist die Ursache.
  • mismatching_state: APP_BASE_URL passt nicht zum aufgerufenen Hostnamen.
  • Lokale Anmeldung gesperrt: Nach fünf Fehlversuchen pro Client und Benutzername wartet die Anmeldung 60 Sekunden, dann länger.

Feste HOST_BIND_IP per DHCP. Startet Docker nach einem Reboot vor dem DHCP-Lease, scheitert der Port-Bind. Abhilfe: net.ipv4.ip_nonlocal_bind=1 per sysctl, oder HOST_BIND_IP auf 0.0.0.0 lassen.

Datenschutz. Per Default landen keine Dokumentinhalte in der Trace-Datenbank, nur Längen und eine kurze Vorschau der Modellantwort. DEBUG=1 in der .env speichert Prompts und Antworten vollständig, dann können Dokumentinhalte in config.db liegen.

Status

Läuft produktiv im Homelab. Auf Robustheit ausgelegt, nicht auf Enterprise-Skala: keine Tests, kein CI, kein Paket. Pull Requests willkommen, kein Support-Versprechen.

Lizenz

MIT