fix: Ghostscript-Angebot log nicht mehr, fehlende Voraussetzungen dokumentiert (v0.7.1)

Befunde aus dem ersten echten Erstinstallations-Test auf frischen Debian-12-
und Debian-13-Containern. Der Weg selbst hat getragen (Basis-Install,
Instanz-Anlage, zweite Instanz, Update mit Rauchtest, Rollback) — diese
Stellen haben gelogen oder gefehlt:

- Das Ghostscript-Backports-Angebot auf Debian 12 war ein garantierter
  Leerlauf, der "aktualisiert ✓" meldete: bookworm-backports enthaelt gar
  kein ghostscript (am Paketindex verifiziert). Die Routine sucht jetzt den
  echten Kandidaten, vergleicht vorher/nachher und raeumt eine nur zur Probe
  angelegte Quelle wieder weg.
- Derselbe untaugliche Rat stand in der Preflight-Meldung, der
  pdfa_level-Warnung, config.example.toml und vier Doku-Dateien — ueberall
  ersetzt durch die echten Optionen.
- Mehrzeilige Log-Hinweise waren durch "echo -e" zerrissen und nicht
  kopierbar; log_* nutzt jetzt printf mit %s.
- pip-freeze.txt landete beim Rollback als /pip-freeze.txt im
  Wurzelverzeichnis, liegt jetzt unter opt/pdf-ocr-hotfolder/.
- git und sudo fehlen auf dem Proxmox-Debian-Template; "sudo ./install.sh"
  scheitert dort. Beide Wege dokumentiert, git als Voraussetzung ergaenzt,
  HTTPS-Clone als Normalfall.
- Rollback: systemctl start kann kein Glob. journald-Reparatur: Instanzen
  danach neu starten, sonst bleibt das Journal leer.

254 Tests gruen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 01:36:42 +02:00
parent cd803a3dfe
commit 465ff8873f
15 changed files with 611 additions and 101 deletions
+134 -18
View File
@@ -14,10 +14,46 @@ Verwandte Dokumente: [README](../README.md) · [Update](UPDATE.md) · [Debian-Ma
| Python | 3.11+ (wegen `tomllib` aus der stdlib); kommt aus der Distribution |
| Arbeitsspeicher | **mindestens 2 GB** für den produktiven Betrieb — siehe [Systemanforderungen](#systemanforderungen) |
| Dateisystem | **ext4, xfs oder zfs**; `incoming/` **lokal**, kein CIFS/NFS — siehe [Dateisystem](#dateisystem-ext4-xfs-oder-zfs) |
| Rechte | `root` (`sudo ./install.sh`) |
| Rechte | `root` — als root direkt `./install.sh`, sonst `sudo ./install.sh` (s. [root oder sudo](#root-oder-sudo)) |
| `git` | zum Klonen des Repos — **nicht** vorinstalliert, s. [Pakete, die fehlen können](#pakete-die-auf-einem-frischen-system-fehlen-können) |
| Netz | apt-Zugriff für die System-Pakete, PyPI-Zugriff für die venv |
| Repo | muss dauerhaft liegen bleiben — `update.sh` kopiert daraus (s. [UPDATE.md](UPDATE.md)) |
### Pakete, die auf einem frischen System fehlen können
Auf dem **Proxmox-Debian-Standard-Template** (12 **und** 13) fehlen zwei Dinge,
die jede Anleitung stillschweigend voraussetzt — am frisch angelegten Container
verifiziert:
| Fehlt | Folge | Abhilfe |
|-------|-------|---------|
| **`git`** | `git clone …` schlägt mit `git: command not found` fehl — und ohne Clone gibt es kein Repo, aus dem `install.sh` läuft | `apt install git` |
| **`sudo`** | der überall dokumentierte Aufruf `sudo ./install.sh` schlägt mit `sudo: command not found` fehl | entweder `apt install sudo`, oder **einfach als `root` ohne `sudo` arbeiten** |
```bash
apt update
apt install -y git # zwingend
apt install -y sudo # nur, wenn nicht als root gearbeitet wird
```
### root oder sudo
Installer und Updater brauchen **root-Rechte** — *wie* man dahin kommt, ist
ihnen gleich. Beide Wege sind gleichwertig:
```bash
# (a) man ist bereits root — im frischen Container der Normalfall
./install.sh
# (b) man arbeitet als normaler Benutzer und hat sudo
sudo ./install.sh
```
In dieser Doku steht durchgehend die Variante mit `sudo`, weil die meisten
Systeme es haben. **Wer als `root` arbeitet, lässt das `sudo` bei jedem Befehl
einfach weg** — das gilt für alle Kommandos in diesem und den übrigen
Dokumenten. Ein fehlendes `sudo` ist kein Grund, es nachzuinstallieren.
Die System-Pakete installiert der Installer selbst. Die Liste steht als
einzige Quelle in `lib/common.sh` (Funktion `pdf_ocr_apt_packages()`, zwischen
den Marken `# --- BEGIN apt-packages` / `# --- END apt-packages`); `install.sh`
@@ -174,14 +210,51 @@ System mehr RAM bekommt.
## Installation
```bash
git clone gitea@gitea.sonith.de:sonith_ug/pdf-ocr-hotfolder.git
apt update && apt install -y git # fehlt im Proxmox-Standard-Template
git clone https://gitea.sonith.de/sonith_ug/pdf-ocr-hotfolder.git
cd pdf-ocr-hotfolder
sudo ./install.sh
sudo ./install.sh # als root: ./install.sh
```
#### Welche Clone-URL?
| Variante | URL | Wann |
|----------|-----|------|
| **HTTPS** (Normalfall) | `https://gitea.sonith.de/sonith_ug/pdf-ocr-hotfolder.git` | braucht **keine** Credentials und funktioniert auf einem frischen Server sofort — der Weg, der im Installations-Test benutzt wurde |
| **SSH** | `gitea@gitea.sonith.de:sonith_ug/pdf-ocr-hotfolder.git` | nur sinnvoll, wenn auf dem Zielsystem ein **Deploy-Key** hinterlegt ist (z.B. weil auch gepusht werden soll) |
> ⚠️ **Der SSH-User bei `gitea.sonith.de` heißt `gitea`, nicht `git`.**
> `git@gitea.sonith.de:…` ist der Default anderer Git-Hoster und hier **falsch**
> — der Clone scheitert dann mit `Permission denied (publickey)`.
`install.sh` ist **Installer und Instanz-Manager in einem** und idempotent —
jeder weitere Aufruf überspringt, was schon steht.
### So sieht ein Erstlauf aus
Verifiziert auf frischen Debian-12- und Debian-13-Containern. Die Reihenfolge
der Abfragen:
1. **LXC-Drop-in** — nur im Container: „systemd-Hardening-Drop-in für LXC
installieren?" → **ja**, sonst scheitert der Start mit `226/NAMESPACE`
([warum](#lxccontainer-error-226namespace)).
2. **Ghostscript-Hinweis** — nur auf Debian 12 mit betroffener Version. Kein
Abbruch: mit dem Default `pdfa_level = ""` ist die Installation
unproblematisch ([Hintergrund](#ghostscript-bug-auf-debian-12)).
3. **journald-Warnung** — nur, wenn `systemd-journald` nicht läuft. Typisch für
Debian 13 in LXC auf Proxmox. Hier **abbrechen**, journald reparieren und neu
anfangen — sonst hat der Dienst kein Log
([Abhilfe](#debian-13-in-lxc-auf-proxmox-journald-scheitert-243credentials)).
4. Dann die **fünf Fragen pro Instanz**: Instanz-Name → Basis-Pfad →
Service-User → OCR-Sprachen → Original-Behandlung (Archiv/löschen/liegen
lassen). Im Detail: [Die Abfragen pro Instanz](#die-abfragen-pro-instanz).
5. Zum Schluss `Weitere Instanz anlegen? [j/N]:` — hier entsteht die zweite
Instanz, ohne dass irgendetwas am Basis-Install noch einmal angefasst wird.
Danach läuft `pdf-ocr-hotfolder@<instanz>.service`. Gegenprobe: eine PDF nach
`incoming/` kopieren und `journalctl -u pdf-ocr-hotfolder@<instanz> -f`
mitlesen.
### Basis-Install vs. Instanz-Anlage
Der Installer unterscheidet zwei Ebenen:
@@ -424,21 +497,40 @@ ocrmypdf-Version:
### Abhilfe
**Weg 1 — Ghostscript anheben** (empfohlen). Der Installer erkennt betroffene
Versionen und bietet auf Debian 12 bookworm-backports an. Manuell:
> 🚫 **Es gibt auf Debian 12 kein neueres Ghostscript.** `bookworm-backports`
> führt **kein** Ghostscript-Paket — am Paketindex geprüft
> (`bookworm-backports/main/binary-amd64`: 2606 Pakete, `ghostscript` nicht
> darunter, `systemd`/`golang-go`/`linux-image-amd64` schon). Ältere Fassungen
> dieser Anleitung und frühere Versionen des Installers haben genau das
> empfohlen — der Rat konnte nie funktionieren.
>
> **Planungsaussage:** Wer auf Debian 12 **PDF/A in der schnellen Betriebsart**
> (`skip_text = true`) braucht, hat dort **keinen Weg** — weder über Backports
> noch sonst. Es bleibt: PDF/A aufgeben, `skip_text` aufgeben (Weg 2, kostet
> Laufzeit) oder Debian 13. **Das gehört vor die Installation**, nicht in den
> Moment, in dem der Preflight abbricht.
```bash
echo 'deb http://deb.debian.org/debian bookworm-backports main' | \
sudo tee /etc/apt/sources.list.d/bookworm-backports.list
sudo apt update && sudo apt install -t bookworm-backports ghostscript
```
Ab Ghostscript 10.02.1 ist alles in Ordnung; PDF/A kann dann eingeschaltet
werden.
**Weg 1 — `pdfa_level = ""` lassen** (Default, empfohlen). Ohne PDF/A-Ausgabe
fasst ocrmypdf ≥ 17 Ghostscript gar nicht an; die betroffene Version ist dann
völlig unproblematisch. Der Preis ist PDF/A — das Ergebnis ist eine normale
durchsuchbare PDF. Für die übliche Anwendung (Scan wird durchsuchbar) reicht
das.
**Weg 2 — `skip_text = false` setzen.** Dann wird vorhandener Text neu erkannt
statt übersprungen, und die Bedingung greift nicht mehr. Das kostet Laufzeit bei
PDFs, die bereits eine Textebene haben.
statt übersprungen, und die Bedingung greift nicht mehr — PDF/A ist damit auch
auf Debian 12 möglich. Das kostet Laufzeit bei PDFs, die bereits eine Textebene
haben, und OCRt sie ein zweites Mal.
**Weg 3 — Distribution mit neuerem Ghostscript.** **Debian 13 liefert
Ghostscript 10.05.1** und ist vom Bug nicht betroffen; dort ist PDF/A zusammen
mit `skip_text = true` ohne Einschränkung nutzbar. Wer PDF/A verbindlich
braucht, installiert von vornherein auf Debian 13.
| Ich brauche … | Debian 12 | Debian 13 |
|---------------|-----------|-----------|
| durchsuchbare PDF, kein PDF/A | ✅ Default (`pdfa_level = ""`) | ✅ |
| PDF/A **und** `skip_text = true` | ❌ kein Weg | ✅ |
| PDF/A mit `skip_text = false` | ✅ (langsamer) | ✅ |
---
@@ -762,6 +854,13 @@ Ist `systemd-journald.service` selbst `failed` (beobachtet mit
`status=243/CREDENTIALS`), gibt es schlicht kein journal, in das geschrieben
werden könnte.
Läuft journald dagegen `active (running)` und das Journal der Instanz ist
trotzdem leer (`-- No entries --`), ist meist journald **erst nach dem Dienst**
wieder hochgekommen: die Startmeldungen hatten in der Zwischenzeit kein Ziel und
sind weg. `sudo systemctl restart 'pdf-ocr-hotfolder@*'` schreibt sie neu —
siehe die Warnung im
[nächsten Abschnitt](#debian-13-in-lxc-auf-proxmox-journald-scheitert-243credentials).
**Einordnung.** Der Dienst loggt seit v0.4.1 **ausschließlich** nach journald —
es gibt bewusst kein eigenes Logfile und kein Logverzeichnis. Ein kaputtes
journald ist damit ein blinder Fleck: jede Fehlersuche läuft ins Leere, und der
@@ -843,9 +942,26 @@ sudo systemctl restart systemd-journald
sudo journalctl --flush
```
Danach `systemctl status systemd-journald` (muss `active (running)` sein) und
`journalctl -u pdf-ocr-hotfolder@<instanz>` gegenprüfen. Für die anderen
betroffenen Units gilt dasselbe Muster mit deren Unit-Namen.
Danach `systemctl status systemd-journald` gegenprüfen — muss `active
(running)` sein. Für die anderen betroffenen Units gilt dasselbe Muster mit
deren Unit-Namen.
> ⚠️ **Jetzt die Instanzen einmal neu starten — sonst steht man vor einem
> leeren Journal.** Wurde der Dienst gestartet, **während** journald tot war,
> sind seine Startmeldungen unwiederbringlich weg: sie hatten kein Ziel. Nach
> der Reparatur meldet `journalctl -u pdf-ocr-hotfolder@<instanz>` dann
> `-- No entries --` — und das sieht exakt so aus wie ein gescheiterter
> Reparaturversuch, obwohl journald längst wieder läuft. Der Neustart schreibt
> die Startmeldungen neu ins frische Journal:
>
> ```bash
> sudo systemctl restart 'pdf-ocr-hotfolder@*'
> journalctl -u pdf-ocr-hotfolder@<instanz> -n 20
> ```
>
> Erst wenn hier die Startmeldungen stehen, ist die Reparatur belegt. (`restart`
> kann das Glob, weil die Units geladen sind — `start` nicht, siehe
> [UPDATE.md](UPDATE.md#rollback).)
> **Der saubere Weg liegt host-seitig.** Das Drop-in kuriert das Symptom im
> Container. Richtig behoben wird es auf dem Proxmox-Host: Update von