DEV Community

Cover image for Paperless-ngx selbst hosten: papierloses Büro mit OCR
serverkueche.de
serverkueche.de

Posted on • Originally published at serverkueche.de

Paperless-ngx selbst hosten: papierloses Büro mit OCR

Rechnungen, Verträge, Behördenpost – der Papierstapel wächst und wächst, und finden tust du
am Ende doch nie etwas. Paperless-ngx macht daraus ein durchsuchbares digitales Archiv: Du wirfst ein
Dokument hinein, es wird per OCR erkannt, verschlagwortet und ist über die
Volltextsuche in Sekunden wieder da. In diesem Rezept setzen wir es hinter Traefik auf.

Was bauen wir?

Am Ende läuft Paperless-ngx 2.20 hinter deinem Traefik-Proxy, erreichbar unter
https://paperless.DEINE_DOMAIN mit HTTPS. Paperless ist ein Dokumenten-Management-System:
Du fütterst es mit Scans oder PDFs, es liest den Text per OCR aus (auch aus reinen
Bild-Scans), erkennt Datum und Inhalt und legt alles durchsuchbar ab. Über Tags,
Korrespondenten und Dokumenttypen bringst du Ordnung hinein; die Volltextsuche findet
später jedes Dokument.

Der Clou ist der Consume-Ordner: Alles, was du dort ablegst (z. B. vom Netzwerk-Scanner),
wird automatisch importiert und verarbeitet. Paperless besteht aus fünf Containern
dem Webserver, einer PostgreSQL-Datenbank, einem Redis-Broker für die
Hintergrundverarbeitung sowie Gotenberg und Tika, die Office-Dokumente in PDF
umwandeln. Die offizielle Vorlage liefert das komplette Gespann.

Der Gewinn gegenüber einem Ordner voller PDFs auf der Festplatte: Paperless macht jedes
Dokument durchsuchbar (auch eingescanntes Papier), hält Original und Archivversion
sauber getrennt und lässt sich per Regeln automatisieren. Deine Unterlagen bleiben dabei
auf deinem Server – kein Cloud-Dienst liest mit, und du bist nicht an ein proprietäres
Format gebunden.

Voraussetzungen

💡 Wie groß muss der Server sein?

Paperless selbst ist genügsam, aber es sind fünf Container, und die OCR-Verarbeitung ist
CPU-lastig
: Beim Erkennen eines Scans läuft ein Kern für einige Sekunden bis Minuten auf
Anschlag. Für den privaten Gebrauch reichen 2 vCPU und 4 GB RAM gut; der getestete VPS
1000 (4 vCore / 8 GB) hat reichlich Luft. Beim Massenimport vieler Dokumente merkst du die
CPU-Last – dann verarbeitet Paperless die Warteschlange eben nach und nach ab.

Unsicher, welche Server-Größe reicht? Der Server-Rechner rechnet dir
RAM- und CPU-Bedarf für deine Dienste aus.

Schritt für Schritt

Schritt 1: DNS-Record anlegen

Lege paperless.DEINE_DOMAIN an (A/AAAA auf deine Server-IP) und prüfe:

dig +short paperless.DEINE_DOMAIN
Enter fullscreen mode Exit fullscreen mode

Es muss deine Server-IP zurückkommen – sonst holt Traefik später kein Zertifikat.

Schritt 2: Einen Secret Key erzeugen

Paperless verschlüsselt Sitzungen mit einem geheimen Schlüssel. Der Default ist öffentlich
bekannt
– bei einer Instanz im Internet ein echtes Risiko. Erzeuge einen eigenen:

head -c 50 /dev/urandom | base64
Enter fullscreen mode Exit fullscreen mode

Kopiere die Ausgabe – sie kommt gleich als PAPERLESS_SECRET_KEY in die Konfiguration.

Schritt 3: Die compose.yaml anlegen

Leg das Projekt an – inklusive der beiden Bind-Mount-Ordner:

mkdir -p ~/paperless/{consume,export} && cd ~/paperless
Enter fullscreen mode Exit fullscreen mode

Die Unterordner consume und export legst du bewusst jetzt, als normaler
Benutzer
an: Würde erst der Docker-Daemon sie beim Start erzeugen, gehörten sie
root – dann könnten weder du (cp in den Consume-Ordner) noch Paperless selbst
(läuft via USERMAP_UID als UID 1000) hineinschreiben.

Erstelle compose.yaml. Ersetze paperless.DEINE_DOMAIN, die Passwörter und den
PAPERLESS_SECRET_KEY:

name: paperless
services:
  broker:
    image: docker.io/library/redis:8
    volumes:
      - redisdata:/data
    networks: [default]
    restart: unless-stopped

  db:
    image: docker.io/library/postgres:18
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: EIN_STARKES_DB_PASSWORT
    volumes:
      - pgdata:/var/lib/postgresql
    networks: [default]
    restart: unless-stopped

  gotenberg:
    image: docker.io/gotenberg/gotenberg:8.34
    command:
      - "gotenberg"
      - "--chromium-disable-javascript=true"
      - "--chromium-allow-list=file:///tmp/.*"
    networks: [default]
    restart: unless-stopped

  tika:
    image: docker.io/apache/tika:3.3.1.0
    networks: [default]
    restart: unless-stopped

  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:2.20.15
    depends_on: [db, broker, gotenberg, tika]
    environment:
      PAPERLESS_REDIS: redis://broker:6379
      PAPERLESS_DBHOST: db
      PAPERLESS_DBUSER: paperless
      PAPERLESS_DBPASS: EIN_STARKES_DB_PASSWORT
      PAPERLESS_TIKA_ENABLED: 1
      PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
      PAPERLESS_TIKA_ENDPOINT: http://tika:9998
      PAPERLESS_URL: https://paperless.DEINE_DOMAIN
      PAPERLESS_SECRET_KEY: DEIN_LANGER_SECRET_KEY
      PAPERLESS_OCR_LANGUAGE: deu
      PAPERLESS_TIME_ZONE: Europe/Berlin
      PAPERLESS_ADMIN_USER: admin
      PAPERLESS_ADMIN_PASSWORD: EIN_STARKES_ADMIN_PASSWORT
      USERMAP_UID: "1000"
      USERMAP_GID: "1000"
    volumes:
      - data:/usr/src/paperless/data
      - media:/usr/src/paperless/media
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.ppl.rule=Host(`paperless.DEINE_DOMAIN`)"
      - "traefik.http.routers.ppl.entrypoints=websecure"
      - "traefik.http.routers.ppl.tls.certresolver=le"
      - "traefik.http.services.ppl.loadbalancer.server.port=8000"
    networks: [default, proxy]
    restart: unless-stopped

volumes:
  data:
  media:
  pgdata:
  redisdata:

networks:
  default:
  proxy:
    external: true
Enter fullscreen mode Exit fullscreen mode

Die wichtigsten Punkte:

  • Nur webserver hängt im proxy-Netz und trägt Traefik-Labels (Port 8000). Die vier Hilfsdienste (db, broker, gotenberg, tika) bleiben intern.
  • PAPERLESS_URL ist Pflicht hinter einem Proxy. Fehlt sie, weist Paperless den Login mit einem CSRF-/„403 Forbidden"-Fehler ab. Sie setzt zugleich die erlaubten Hosts und die vertrauenswürdigen Ursprünge.
  • PAPERLESS_OCR_LANGUAGE: deu stellt die Texterkennung auf Deutsch. Deutsch, Englisch und ein paar weitere Sprachen sind im Image bereits enthalten – kein Zusatzpaket nötig.
  • PAPERLESS_ADMIN_USER / _PASSWORD legen beim ersten Start automatisch den Superuser an, sodass du dich direkt anmelden kannst.
  • USERMAP_UID/GID sollten zur Kennung deines Server-Benutzers passen (per id -u bzw. id -g ermitteln, meist 1000). Sonst gibt es „Permission denied" im Consume-Ordner.
  • export und consume sind bewusst Ordner im Projektverzeichnis (Bind-Mounts): consume ist der Eingangskorb, export das Ziel für Backups.

Paperless nutzt insgesamt vier Speicherbereiche, die du auseinanderhalten solltest:
media enthält deine verarbeiteten Dokumente (das Herzstück!), data den Suchindex und
Hilfsdaten, consume ist der Eingangskorb und export das Backup-Ziel. Fürs Backup zählen
media und data sowie die Datenbank – genau das nimmt dir der document_exporter weiter
unten ab.

Schritt 4: Starten und anmelden

Zieh die Images (mehrere GB) und starte:

docker compose up -d
docker compose logs -f webserver
Enter fullscreen mode Exit fullscreen mode

Beim ersten Start richtet Paperless die Datenbank ein (Migrationen) – das dauert einen
Moment. Prüfe, dass alle fünf Container laufen:

docker compose ps
Enter fullscreen mode Exit fullscreen mode

Du solltest webserver, db, broker, gotenberg und tika mit Status running sehen
(der webserver wird nach kurzer Zeit healthy). Ist der Worker bereit (celery@… ready
im Log), ruf https://paperless.DEINE_DOMAIN auf. Es erscheint die Anmeldeseite:

Die Anmeldeseite von Paperless-ngx unter der eigenen Domain

Melde dich mit admin und deinem Passwort an. Du landest auf der Startseite mit einer
kurzen Willkommensmeldung und ersten Statistiken. Ganz unten links siehst du die laufende
Version – praktisch, um vor einem Update den Ausgangsstand zu kennen. Die Sprache
kannst du bei Bedarf unter Einstellungen umstellen; standardmäßig folgt Paperless der
Sprache deines Browsers:

Die Startseite von Paperless-ngx mit Willkommensmeldung und Statistik-Widget

Schritt 5: Das erste Dokument einlesen

Jetzt der Kern. Es gibt drei Wege, ein Dokument hineinzubekommen:

  1. Über die Weboberfläche: oben rechts auf Dokumente hochladen und eine PDF- oder Bilddatei auswählen.
  2. Über den Consume-Ordner: Leg eine Datei in ~/paperless/consume – Paperless erkennt sie automatisch, verarbeitet sie und löscht sie danach aus dem Ordner. Ideal für einen Netzwerk-Scanner, der direkt dorthin scannt.
  3. Aus einem Postfach: Paperless kann unter E-Mail ein IMAP-Konto abrufen und Anhänge automatisch einlesen – praktisch für Rechnungen, die dir ohnehin per Mail kommen.
cp ~/eine-rechnung.pdf ~/paperless/consume/
Enter fullscreen mode Exit fullscreen mode

Paperless nimmt PDFs, Bilder (JPG/PNG/TIFF) und – dank Gotenberg und Tika – auch
Office-Dateien wie Word oder Excel an. Bei einem reinen Bild-Scan liest die OCR den Text
aus und legt ihn als durchsuchbare Ebene über das Dokument; bei einem PDF mit vorhandenem
Textlayer überspringt Paperless die Erkennung und ist entsprechend schneller. Das Original
bleibt dabei unangetastet erhalten – Paperless erzeugt zusätzlich eine durchsuchbare
Archiv-Version.

Nach ein paar Sekunden (OCR braucht etwas Zeit) taucht das Dokument unter Dokumente auf –
mit einer Vorschau und dem erkannten Titel:

Die Dokumentenliste von Paperless-ngx mit einem verarbeiteten Dokument als Kachel

Ein Klick öffnet die Detailansicht: links die Metadaten (Titel, Datum, Korrespondent,
Tags) und die Reiter für Inhalt, Metadaten und Verlauf, rechts das Dokument mit einer
zoombaren Vorschau. Paperless hat aus dem Scan bereits das Datum erkannt und
schlägt es zur Bestätigung vor – genau das leistet die OCR im Hintergrund für dich:

Die Detailansicht eines Dokuments in Paperless-ngx mit Metadaten links und dem erkannten Dokument rechts

Schritt 6: Ordnung mit Tags, Korrespondenten & Dokumenttypen

Damit die Suche später greift, vergibst du Tags (z. B. Steuer, Versicherung),
ordnest einen Korrespondenten (den Absender) und einen Dokumenttyp (Rechnung,
Vertrag …) zu. Das kannst du von Hand machen – oder Paperless über Arbeitsabläufe
automatisieren: Regeln, die eingehende Dokumente anhand ihres Inhalts automatisch
verschlagworten. So sortiert sich dein Archiv mit der Zeit von selbst.

Die Volltextsuche oben durchsucht danach nicht nur Titel und Tags, sondern den
kompletten erkannten Text – eine Suche nach Rechnungsbetrag oder einem Kundennamen findet
das passende Dokument in Sekunden. Kombiniert mit den Filtern (Korrespondent, Zeitraum,
Dokumenttyp) wird der Papierstapel endgültig zum durchsuchbaren Archiv.

Ein einfaches Beispiel für einen Arbeitsablauf: Enthält ein neues Dokument das Wort
„Stromabrechnung", vergib automatisch den Tag Energie, setz den Korrespondenten auf deinen
Stromanbieter und den Dokumenttyp auf Rechnung. Solche Regeln legst du unter
Verwaltung → Arbeitsabläufe an; sie greifen bei jedem eingehenden Dokument. Anfangs
lohnt es sich, ein paar Dokumente von Hand zu sortieren – daraus siehst du schnell, welche
Regeln sich wiederholen und automatisieren lassen. Nach ein paar Wochen landet der Großteil
deiner Post ohne dein Zutun am richtigen Platz.

💡 Scanner direkt in den Consume-Ordner

Der volle Komfort entsteht mit einem Dokumentenscanner. Richte auf dem Server eine
Netzwerkfreigabe (z. B. Samba) ein, die auf ~/paperless/consume zeigt, und stelle deinen
Scanner so ein, dass er dorthin scannt. Ab dann gilt: Blatt einlegen, Knopf drücken – wenige
Sekunden später ist das Dokument erkannt, verschlagwortet und durchsuchbar im Archiv. Für
unterwegs gibt es zudem Community-Apps (z. B. „Paperless Mobile"), die sich mit deiner
Instanz verbinden.

⚠️ Deine Unterlagen hängen im Internet

In Paperless liegen sensible Dokumente – Rechnungen, Verträge, Behördenpost. Sobald die
Instanz über paperless.DEINE_DOMAIN erreichbar ist, steht die Anmeldeseite offen im Netz.
Vergib deshalb ein langes, einmaliges Passwort, und aktiviere unter Einstellungen die
Zwei-Faktor-Authentifizierung. Wer maximale Sicherheit will, macht Paperless nur über ein
VPN erreichbar – für ein reines Privatarchiv, das nur du nutzt, ist das eine Überlegung wert.

Wenn es nicht funktioniert

Symptom: Beim Login erscheint „Forbidden (403)" oder „CSRF verification failed".

Ursache & Lösung: PAPERLESS_URL ist nicht oder falsch gesetzt. Sie muss exakt deiner
HTTPS-Adresse entsprechen (https://paperless.DEINE_DOMAIN, ohne Schrägstrich am Ende).
Nach der Korrektur docker compose up -d.

Symptom: Dateien im Consume-Ordner werden nicht verarbeitet, „permission denied".

Ursache & Lösung: Häufigste Ursache: Die Ordner wurden nicht vorab angelegt
(Schritt 3), sondern beim ersten Start vom Docker-Daemon erzeugt – dann gehören sie
root. Mit sudo chown -R $(id -u):$(id -g) ~/paperless/consume ~/paperless/export
gehören sie wieder dir. Ansonsten: USERMAP_UID/USERMAP_GID passen nicht zum
Besitzer des Ordners – ermittle deine Kennung mit id -u und id -g, trag die Werte
ein und starte neu.

Symptom: Hochgeladene Dokumente bleiben „in Bearbeitung" hängen.

Ursache & Lösung: Die Hintergrundverarbeitung läuft über Redis. Prüfe, dass der
broker-Container läuft, und sieh unter Dateiaufgaben nach der Fehlermeldung der
fehlgeschlagenen Aufgabe.

Symptom: Die Texterkennung liefert Unsinn oder erkennt nichts.

Ursache & Lösung: Falsche OCR-Sprache. Setz PAPERLESS_OCR_LANGUAGE=deu (oder
deu+eng für gemischte Dokumente). Nur installierte Sprachen funktionieren.

Symptom: Office-Dokumente (Word, Excel) werden nicht angenommen oder enden im Timeout.

Ursache & Lösung: Dafür sind Gotenberg und Tika zuständig. Prüfe, dass beide Container
laufen und PAPERLESS_TIKA_ENABLED=1 samt der beiden Endpoint-Variablen gesetzt ist.

Symptom: Beim Massenimport wird der Server sehr langsam, die CPU ist dauerhaft am Anschlag.

Ursache & Lösung: OCR ist rechenintensiv, und Paperless nutzt standardmäßig alle Kerne.
Auf kleinen Servern kannst du die Last drosseln, indem du die Zahl der Worker bzw. Threads
begrenzt (PAPERLESS_TASK_WORKERS, PAPERLESS_THREADS_PER_WORKER). Dann dauert der Import
länger, aber die Oberfläche bleibt bedienbar.

Wartung & Backups

  • Das saubere Backup macht der document_exporter. Er schreibt alle Dokumente, Vorschaubilder, Metadaten und den Datenbankinhalt in den export-Ordner – portabel und wieder importierbar:
  docker compose exec -T webserver document_exporter ../export
Enter fullscreen mode Exit fullscreen mode

Sichere den export-Ordner anschließend verschlüsselt und off-site mit
Restic. Alternativ sicherst du die Volumes media,
data und die Datenbank direkt – der Exporter ist aber der empfohlene, umzugssichere Weg.

  • Beim Wiederherstellen die gleiche Version verwenden. Ein Export enthält ein Abbild passend zum Datenbank-Schema; spiel ihn nur in eine Paperless-Instanz derselben Version ein (document_importer ../export).
  • Updates. Vor dem Update ein Backup ziehen, dann den Image-Tag erhöhen (z. B. 2.20.15 → nächste Version), docker compose pull und docker compose up -d. Die Datenbank-Migrationen laufen beim Start automatisch. Bleib bei der stabilen 2.x-Reihe – die 3.0-Beta ist noch nicht für den Produktivbetrieb gedacht.
  • Backup automatisieren. Den document_exporter legst du am besten in einen täglichen Cron-Job (z. B. nachts), der anschließend den export-Ordner per Restic sichert. So hast du jeden Morgen einen frischen, wiederherstellbaren Stand – ohne daran denken zu müssen.
  • Ehrlich zum Aufwand: Paperless läuft danach sehr wartungsarm. Der eigentliche Aufwand ist das Einsortieren neuer Dokumente – das nimmt dir mit etwas eingerichteter Automatik aber zunehmend die Software ab. Plane einmal die grobe Tag-Struktur, dann trägt sich das Archiv weitgehend selbst.

Dieser Beitrag erschien zuerst auf serverkueche.de.

Top comments (0)