Paperless NGX

Paperless NGX ist eine einfach zu bedienende Lösung zur Verwaltung von Dokumenten. Es kann PDF-Dateien, Office-Dokumente, Bilddateien und Mails verarbeiten.

Screenshot: Dokumente in Paperless NGX
Abb. 1: Screenshot: Dokumente in Paperless NGX

Installation

Vorbereitung Docker

Zunächst wird eine Docker-Laufzeitumgebung benötigt. Ubuntu bringt eine Docker-Umgebung mit. Allerdings funktioniert diese mitgelieferte Umgebung oftmals und hier konkret mit den Paperless-Paketen nicht. Darum ist eine Installation von Docker auf der Grundlage der Docker-Dokumentation zuverlässiger (s. https://docs.docker.com/engine/install/ubuntu/). Das habe ich in dem Beitrag über Docker beschrieben.



Installation Paperless NGX mittels Docker-Compose-File

Wenn ich mich auf der SSH-Konsole des Servers angemeldet habe, dann bewege ich mich im Homeshare des angegebenen Users (also z.B. /home/andreas/). Hier erstelle ich einen Ordner paperless-nxg und wechsele dort hinein mit


mkdir paperless-nxg && cd paperless-ngx
Für Paperless NGX muss hier nun nur eine Datei docker-compose.yml angelegt werden mit

nano docker-compose.yml
mit folgendem Inhalt:

services:
  broker:
    image: docker.io/library/redis:8.4
    restart: unless-stopped
    volumes:
      - redisdata:/data

  db:
    image: postgres:alpine
    restart: unless-stopped
    volumes:
      - ./db:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: paperless
      POSTGRES_USER: paperless
      POSTGRES_PASSWORD: paperless

  webserver:
    image: ghcr.io/paperless-ngx/paperless-ngx:2.19.1
    restart: unless-stopped
    depends_on:
      - db
      - broker
      - gotenberg
      - tika
    ports:
      - "8000:8000"
    volumes:
      - ./data:/usr/src/paperless/data
      - ./media:/usr/src/paperless/media
      - ./export:/usr/src/paperless/export
      - ./consume:/usr/src/paperless/consume
    environment:
      PAPERLESS_URL: [Domain oder leer lassen]
      PAPERLESS_TIME_ZONE: 'Europe/Berlin'
      PAPERLESS_OCR_LANGUAGE: deu+eng
      PAPERLESS_SECRET_KEY: 'echt komplexes, geheimes Passwort wie z.B. 123456'
      PAPERLESS_REDIS: redis://broker:6379
      PAPERLESS_DBHOST: db
      PAPERLESS_DBNAME: paperless
      PAPERLESS_DBUSER: paperless
      PAPERLESS_DBPASS: paperless
      PAPERLESS_TIKA_ENABLED: 1
      PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
      PAPERLESS_TIKA_ENDPOINT: http://tika:9998

  gotenberg:
    image: docker.io/gotenberg/gotenberg:8.24
    restart: unless-stopped

    # Beim Konvertieren von .eml-Files mit Gotenberg soll 
    # externer content wie z.B: tracking pixels oder javascript
    # nicht mit konvertiert werden
    command:
      - "gotenberg"
      - "--chromium-disable-javascript=true"
      - "--chromium-allow-list=file:///tmp/.*"

  tika:
    image: docker.io/apache/tika:latest
    restart: unless-stopped

volumes:
  redisdata:
Hier wird zunächst Redis, die In-Memory-Komponente zur Beschleunigung der Datenbankzugriffe, definiert. Redis bekommt hier ein Volume data unter dem Namen redisdata im aktuellen Pfad zugewiesen. Dann wird die Datenbank postgres in der Version alpine mit dem persistenten Volume data definiert. Die Volume-Definition ist wichtig, damit nach einem Neustart des Servers bzw. Containers die Daten noch vorhanden sind. Die Credentials für die Datenbank werden in den Environment-Variablen für die Services db und webserver (natürlich identisch) definiert. Dann werden die Services tika und gotenberg definiert, damit Paperless-NGX Office-Formate und eMails verarbeiten kann. Hier ist im Service eine kleine Besonderheit eingebaut: Es werden chromium-Features genutzt, um Java-Script, Tracking-Pixel und andere unerwünschte externe Links auszuschließen. Die Restart-Policy "unless-stopped" sorgt dafür, dass die Container nach einem Reboot des Servers wieder gestartet werden, es sei denn, sie wurden vorher ausdrücklich gestoppt.

Paperless-NGX kann ich nun starten mit

docker compose up -d
Das System startet, was eine Weile dauert. Den Erfolg kann ich zwischendurch mit

docker ps
oder ausführlicher mit

docker logs paperless-nxg-webserver-1
ansehen. Wenn keine Fehler aufgetreten sind, dann sollte Paperless NGX starten und unter der eingetragenen Domain, so sie denn erreichbar ist oder unter der IP-Adresse des Servers mit der Portnummer 8000 angesprochen werden können.



Freigabe des Consume-Ordners für den Scanner

Damit direkt in das DMS gescannt werden kann, muss der Scanner Dateien im Consume-Ordner ablegen können. Wenn dazu das SMB-Protokoll genutzt werden soll, dann ist auf dem DMS-Server ein Samba-Server zu installieren und eine entsprechende Freigabe einzurichten. Die Freigabe wird in der Datei "/etc/samba/smb.conf" eingetragen:


 [paperless]
      comment = Paperless Eingangsordner
      path = /home/andreas/paperless-ngx/paperless-ngx/consume
      browsable = yes
      read only = no
      guest ok = no

Nach Aktivierung dieser Freigabe auf dem Sambaserver ist der Consume-Ordner als Freigabe im Netz verfügbar. Verarbeitbare Dateien (Office-Dateien, Mails, Textdateien, Grafiken und natürlich PDF), die in diesen Ordner geschrieben werden, werden von Paperless-NGX verarbeitet.



Datensicherung

Mein DMS-Server, ein LXC auf einem Proxmox-Host, wird jede Nacht auf den Proxmox-Backup-Server gesichert und kann komplett zurück gesichert werden und es kann auch ein Filerestore vorgenommen werden. Da für den PBS eine Retentionregel nach dem Grandfather-Father-Son-Prinzip eingerichtet ist, kann jederzeit auf die Stände der letzten Tage und Wochen zurück gesichert werden. Zu dieser Retention-Regel habe ich in meinem Youtube-Video (s. hier: Video) einiges erklärt.

Zur Offsite-Sicherung wird jeden Tag um 11:30 Uhr ein Export der Daten angestoßen und diese exportierten Daten dann um 12:00 Uhr verschlüsselt und inkrementell per duplicati auf einen entfernten Server übertragen. Ich habe duplicati in meiner Umgebung auf einem anderen Server installiert als den Paperless-NGX-Server. Darum muss ich dafür sorgen, dass duplicati auf die Sicherungsdaten zugreifen kann (s.u.).

Das Exportverzeichnis ist ja mittels der oben aufgeführten docker-compose.yml persistent eingerichtet. Hier hinein werden per cronjob und exporter die Export-Dateien abgelegt werden. Dazu richte ich den Cronjob mit


sudo nano /etc/crontab
ein und ergänze die Systemdatei um folgenden Eintrag:

30 11   * * *   andreas docker exec paperless-webserver-1 document_exporter /usr/src/paperless/data/export
So wird jeden Tag um 11:30 Uhr ein Export angestoßen. Der Exporter legt dabei alle Dokumente im Ursprungsformat, ihre jeweiligen PDF-Repräsentationen und Webvorschaubilder, eine Datei namens manifest.json mit allen Metadaten sowie eine Datei metadata.json mit der Angabe der Versionsnummer von Paperless-NGX in dem angegebenen Verzeichnis ab.

Dieses Verzeichnis ist per Samba freigegeben. Dazu steht in der Datei "/etc/samba/smb.conf" des DMS-Servers:

 [export]
   comment = Export von Paperless-NGX
   path = /home/andreas/paperless-ngx/paperless-ngx/data/export
   browsable = yes
   read only = no
   guest ok = no
Dieses Verzeichnis ist auf dem Server, auf dem Duplicati läuft, unter "/export" gemounted:

//10.10.0.110/export /export cifs vers=3.0,username=ichhalt,password=**********,uid=1000,gid=1000 0 0
In der Datei "docker-compose.yml" für Ducati ist dieses Verzeichnis als Volume eingetragen:

volumes:
         ...
         - /export:/dms-export
In Duplicati ist nun ein Sicherungsjob namens "dms", eingerichtet, der die Daten täglich um 12:00 Uhr incrementell und verschlüsselt in das Verzeichnis "/backup/dms" sichert. Das Verzeichnis "backup" ist in der Datei "docker-compose.yml" als Volume mit dem Ziel "/remote-backup" eingetragen. Das Verzeichnis "/remote-backup" auf dem Duplicati-Server ist eine SMB-Freigabe auf einen vServer von Netcup, auf den per Wireguard-Tunnel zugegriffen wird, und die auf dem Duplicati-Server gemounted ist.

Die nachfolgende Grafik veranschaulicht das Prinzip (hoffentlich):
Schaubild: Datensicherung auf entfernten Server
Abb. 2: Schaubild der Datensicherung auf entfernten Server



Absicherung

Der Zugriff auf die Anwendung kann abgesichert werden, indem mittels Nginx Proxy Manager HTTPS-Zugriffe ermöglicht (und erzwungen) werden. Außerdem kann eine Zwei-Faktor-Authentifizierung mit Authelia oder Authentik realisiert werden. Wenn die Anwendung über das Internet zugänglich ist, dann sollte das auf jeden Fall gemacht werden.



Updates

Updates können bequem durch Aktualisierung Container durchgeführt werden. Dazu wechselt man zunächst auf der Linux-Konsole in den Ordner mit der entsprechenden YAML-Datei (docker-compose.yml) und setzt dort den Befehl zum Stoppen der laufenden Container ab, pullt die neueste Version und startet die Container wieder:


docker compose down && docker compose pull && docker compose up -d
Wenn das ohne Fehlermeldungen durchgelaufen ist, dann ist die Paperless NGX-Instanz aktualisiert.



Migration / Umzug

Für eine Migration oder einen Umzug müssen zunächst die Quell- und die Zielinstanz in der selben Version vorliegen. Ggf. ist zunächst ein Update durchzuführen. Dann wird von der Quellinstanz der Export durchgeführt:



docker exec -it paperless-webserver-1 document_exporter ../data/export
Die Daten liegen dann im Verzeichnis ../data/export (also z.B. "/home/andreas/paperless-ngx/data/export"). Zum Importieren müssen sie zunächst auf den Zielserver übertragen werden. Wenn sie in den oben genannten Ordner kopiert wurden, dann können sie nun mit dem Befehl

docker exec -it paperless-webserver-1 document_importer ../data/export
importiert werden. Dadurch wird die Datenbank überschrieben und alle Daten werden importiert. Der Name des betreffenden Containers (hier "paperless-webserver-1" genannt) muss natürlich passen. Er kann mit

docker ps
ausgelesen werden.



Trouble Shooting

Wenn der Webserver nach einem Neustart des Servers nicht auf Port 8000 lauscht, dann hilft es, zunächst die Firewall des Server temporär zu deaktivieren und den Webserver neu zu starten. Danach kann die Firewall wieder aktiviert werden.