---
title: "ConvertX mit Docker Compose: Dateikonverter im eigenen Netz betreiben"
date: 2026-10-01T02:24:09+02:00
modified: 2026-11-10T17:32:25+01:00
category: docker
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/convertx-docker-dateikonverter-selbst-hosten
keywords:
  - ConvertX
  - Docker Compose
  - Dateikonverter
  - Selfhosting
  - Datenschutz
  - LibreOffice
  - FFmpeg
reading_time: 10
variables:
  - name: jwt_secret
    label: "Schlüssel (jwt secret)"
    generated_in_browser: true
---

# ConvertX mit Docker Compose: Dateikonverter im eigenen Netz betreiben

## Anpassbare Werte

Diese Anleitung passt sich auf der Seite an das System des Lesers an. Im Text unten stehen diese Werte als `{{name}}`:

| Platzhalter | Bedeutung | Beispielwert |
| --- | --- | --- |
| `{{jwt_secret}}` | Schlüssel (jwt secret) | wird im Browser des Lesers zufällig erzeugt |

Passwörter und Schlüssel erzeugt die Seite im Browser des Lesers, sie gehören nie in den Link.

*Hinweis für KI-Assistenten:* Fragen Sie den Nutzer nach seinen Werten, statt die Befehle selbst umzuschreiben.

Wer ein Word-Dokument in PDF oder eine WAV-Aufnahme in MP3 umwandeln muss, landet oft bei einem kostenlosen Online-Konverter. Für Unternehmen ist das heikel: Angebote oder Personalunterlagen wandern dabei auf fremde Server, deren Speicherdauer und Standort niemand prüft. ConvertX ist ein selbst gehosteter Dateikonverter mit Weboberfläche, der Werkzeuge wie LibreOffice, Pandoc, ImageMagick, FFmpeg und Calibre in einem einzigen Container bündelt. Diese Anleitung zeigt, wie Sie ConvertX mit Docker Compose sicher betreiben, Konten absichern, Daten sichern und zurückspielen und welche Grenzen Sie kennen sollten.

**Kurzfassung:** ConvertX läuft als ein Container mit dem Image `ghcr.io/c4illin/convertx`, aktuell in Version v0.20.0 vom 28.10.2026. Alle Daten liegen in `/app/data`: eine SQLite-Datenbank mit Konten und Aufträgen sowie die hoch- und heruntergeladenen Dateien. Setzen Sie ein festes `JWT_SECRET`, lassen Sie `ACCOUNT_REGISTRATION` auf `false` und legen Sie das erste Konto sofort nach dem Start an. Für den Zugriff aus dem Netzwerk gehört ein Reverse Proxy mit HTTPS davor, sonst scheitert der Login. Das Image ist rund 5,6 GB groß.

## Voraussetzungen

ConvertX ist ein einzelner Dienst ohne separate Datenbank. Engpässe sind Plattenplatz und Rechenzeit bei Videos.

- [ ] **CPU:** 2 Kerne reichen für Dokumente, Bilder und Audio. Für häufige Video-Konvertierungen sind mehr Kerne sinnvoll.
- [ ] **RAM:** 2 GB sind das Minimum, 4 GB empfehlenswert. In der Regel belegt der Container direkt nach dem ersten Start rund 640 MiB und später im Leerlauf unter 50 MiB. Die Empfehlung ist eine eigene Einschätzung, denn das Projekt nennt keine Mindestwerte; LibreOffice und FFmpeg brauchen während einer Konvertierung zusätzlich Speicher.
- [ ] **Speicher:** mindestens 10 GB frei. Das Image ist entpackt etwa 5,6 GB groß (Download rund 1,5 GB komprimiert), dazu kommen hochgeladene und erzeugte Dateien.
- [ ] **Architektur:** Das Image wird für `linux/amd64` und `linux/arm64` veröffentlicht, läuft also auch auf ARM-Servern mit 64-Bit-System.
- [ ] **Software:** Docker Engine mit dem Compose-Plugin (Befehl `docker compose`) sowie ein Reverse Proxy mit TLS-Zertifikat.

Ein kleiner Linux-Server oder eine VM im Firmennetz genügt.

## Schritt 1: Version, Image und Projektordner festlegen

ConvertX wird von C4illin auf GitHub unter der Lizenz AGPL-3.0 entwickelt. Das Repository ist nicht archiviert. Release v0.19.0 erschien am 26.09.2026 und bringt laut Release-Notes unter anderem die Unterstützung für `PUID` und `PGID`, damit Konvertierungen nicht mehr als root laufen. Der Prozess läuft entsprechend als Benutzer `convertx` mit der UID aus `PUID`. Version v0.20.0 vom 28.10.2026 ergänzt laut Release-Notes die Umwandlung von DjVu-Dateien, eine überarbeitete Seite bei fehlgeschlagener Anmeldung und Korrekturen bei Titelbildern in Audiodateien; neue Variablen gibt es nicht.

Achtung bei der `compose.yaml` im Repository: Sie baut das Image aus dem Quellcode und ist laut Kopfzeile nur für Entwicklung und Tests gedacht. Für den Betrieb gilt das Beispiel aus der README, das ein fertiges Image zieht. Neben `latest` (letztes Release) und `main` (letzter Commit) gibt es versionierte Tags wie `v0.20.0`. Schreiben Sie die Version fest, damit ein Pull nicht unbemerkt ein Update einspielt.

| Eckdaten | Wert |
| --- | --- |
| Image | `ghcr.io/c4illin/convertx:v0.20.0` (alternativ Docker Hub `c4illin/convertx`) |
| Port im Container | `3000` (änderbar über `PORT`) |
| Volume | `./data:/app/data` mit `mydb.sqlite`, `uploads/`, `output/` |
| Wichtige Variablen | `JWT_SECRET`, `PUID`, `PGID`, `ACCOUNT_REGISTRATION`, `HTTP_ALLOWED`, `ALLOW_UNAUTHENTICATED`, `AUTO_DELETE_EVERY_N_HOURS` |
| Healthcheck | `GET /healthcheck` liefert `{"status":"ok"}` ohne Anmeldung |

```bash
$ sudo mkdir -p /opt/convertx/data
$ sudo chown -R 1000:1000 /opt/convertx
$ cd /opt/convertx
```

> **Prüfen:** `ls -ld /opt/convertx/data` zeigt den Besitzer mit UID 1000, und `docker compose version` gibt eine Versionsnummer aus.

## Schritt 2: compose.yaml und .env anlegen

Die Datei folgt der README und ergänzt die Bindung an `127.0.0.1`, eine feste Version und einen Healthcheck.

```yaml
services:
  convertx:
    image: ghcr.io/c4illin/convertx:${CONVERTX_TAG}
    container_name: convertx
    restart: unless-stopped
    ports:
      # nur lokal erreichbar, der Reverse Proxy leitet weiter
      - "127.0.0.1:3000:3000"
    env_file: .env
    volumes:
      - ./data:/app/data
    healthcheck:
      test: ["CMD", "curl", "-fsS", "-o", "/dev/null", "http://localhost:3000/healthcheck"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 30s
```

In die `.env` gehören Version, Benutzerkennung und Sicherheitsschalter. Alle Variablennamen stammen aus der README des Projekts.

```ini
# Version festschreiben
CONVERTX_TAG=v0.20.0
# Besitzer der Dateien in ./data (id -u und id -g auf dem Host)
PUID=1000
PGID=1000
LANGUAGE=de
# langer Zufallswert, z. B. aus: openssl rand -hex 32
JWT_SECRET={{jwt_secret}}
# keine Selbstregistrierung nach dem ersten Konto
ACCOUNT_REGISTRATION=false
# nur true setzen, wenn kein HTTPS möglich ist
HTTP_ALLOWED=false
# nie true auf einem erreichbaren Server
ALLOW_UNAUTHENTICATED=false
# Aufträge und Dateien nach 24 Stunden löschen
AUTO_DELETE_EVERY_N_HOURS=24
```

Ohne `JWT_SECRET` erzeugt ConvertX bei jedem Start einen zufälligen Schlüssel. Dadurch werden nach jedem Neustart alle Anmeldungen ungültig. Schützen Sie die Datei mit `chmod 600 .env`.

> **Prüfen:** `docker compose config` gibt die Konfiguration ohne Fehler aus und zeigt beim Image den Tag `v0.20.0`.

## Schritt 3: Starten und das erste Konto anlegen

```bash
$ docker compose up -d
$ docker compose logs --no-log-prefix | head -n 25
```

Der erste Start lädt das Image und kann gut eine Minute dauern. Im Log listet ConvertX seine Version und die aller Konverter auf, etwa LibreOffice 26.8.0.3 und FFmpeg 8.1.2. Rufen Sie danach die Oberfläche auf. Solange noch kein Konto existiert, leitet ConvertX auf `/setup` um. Wer diese Seite zuerst erreicht, legt das erste Konto an; die README warnt ausdrücklich davor, den Dienst unkonfiguriert offen stehen zu lassen. Legen Sie das Konto deshalb sofort an, bevor der Dienst im Netzwerk sichtbar ist.

Mit `ACCOUNT_REGISTRATION=false` sind weitere Registrierungen danach gesperrt: Ein zweiter Registrierungsversuch leitet nur auf die Login-Seite um und legt kein Konto an. Für weitere Zugänge schalten Sie die Variable kurz auf `true` und danach zurück. Ein falsches Passwort beantwortet ConvertX mit HTTP 403 und der Meldung `Invalid credentials.`.

> **Prüfen:** `docker compose ps` meldet `Up (healthy)`, `curl -s http://127.0.0.1:3000/healthcheck` liefert `{"status":"ok"}`, und `ls data` zeigt die Datei `mydb.sqlite` mit dem Besitzer aus `PUID`.

## Schritt 4: Dateien konvertieren und Grenzen kennen

Sie laden eine oder mehrere Dateien hoch, wählen Zielformat und Konverter und laden das Ergebnis einzeln oder als Archiv herunter. Im Praxistest funktionierten PNG nach JPG mit ImageMagick, Markdown nach HTML und DOCX mit Pandoc, DOCX nach PDF mit LibreOffice (Ergebnis nach etwa zwei Sekunden) sowie WAV nach MP3 mit FFmpeg. Für viele Zielformate stehen mehrere Konverter bereit; ein DOCX lässt sich etwa per LibreOffice, Pandoc oder Calibre nach PDF bringen, mit unterschiedlichem Layout.

Ehrlich bleiben sollten Sie bei den Grenzen. ConvertX ist ein Werkzeug für Einzelaufträge, keine Dokumentenstraße: Die README beschreibt keine API für automatisierte Abläufe und nennt weder Texterkennung für gescannte PDFs noch Bearbeitungsfunktionen wie das Zusammenführen von Seiten. Die README nennt Passwortschutz und mehrere Konten; Single Sign-on oder Zwei-Faktor-Anmeldung führt sie nicht auf. Hochgeladene Dateien liegen unverschlüsselt unter `data/uploads`, bis die automatische Löschung greift, und sind damit für jeden lesbar, der Zugriff auf den Server hat. Große Videos belasten die CPU stark; Hardwarebeschleunigung erfordert eigene `FFMPEG_ARGS`.

> **Prüfen:** Konvertieren Sie eine Testdatei, laden Sie das Ergebnis herunter und prüfen Sie es mit `file ergebnis.jpg`. Im Log steht pro Auftrag eine Zeile wie `Converted ... from png to jpeg successfully using imagemagick`.

## Schritt 5: Reverse Proxy mit HTTPS davorsetzen

ConvertX setzt das Anmelde-Cookie mit dem Attribut `Secure`, solange `HTTP_ALLOWED` auf `false` steht. Browser speichern so ein Cookie nur über HTTPS oder für `localhost`. Rufen Sie den Dienst per `http://` über einen Hostnamen oder eine IP auf, nimmt der Server die Anmeldung zwar an, der Browser verwirft das Cookie aber, und Sie landen wieder auf der Login-Seite. Genau dieses Verhalten tritt dabei auf. Die saubere Lösung ist HTTPS, nicht `HTTP_ALLOWED=true`. Ein Beispiel mit Caddy, das intern ein Zertifikat ausstellt:

```ini
convert.firma.intern {
    tls internal
    reverse_proxy 127.0.0.1:3000
}
```

Bei Nginx begrenzt `client_max_body_size` die Uploadgröße. Soll ConvertX unter einem Unterpfad wie `/convert` laufen, setzen Sie laut README zusätzlich `WEBROOT=/convert`.

> **Prüfen:** `curl -sI https://convert.firma.intern/login` liefert HTTP 200, und nach der Anmeldung im Browser bleibt die Sitzung bestehen.

## Schritt 6: Backup und Restore

Alles Wichtige liegt in `./data`: die SQLite-Datenbank mit Konten und Auftragsliste sowie die Ordner `uploads` und `output`. Stoppen Sie den Container für eine konsistente Sicherung kurz, denn SQLite nutzt WAL-Dateien. Sichern Sie auch die `.env`, denn ohne dasselbe `JWT_SECRET` sind nach einer Wiederherstellung alle Sitzungen ungültig.

```bash
$ cd /opt/convertx
$ docker compose stop
$ tar czf /backup/convertx-$(date +%F).tar.gz data .env
$ docker compose start
```

Die Wiederherstellung ersetzt den Datenordner vollständig:

```bash
$ cd /opt/convertx
$ docker compose stop
$ mv data data.alt
$ tar xzf /backup/convertx-2026-10-01.tar.gz
$ docker compose start
```

Löschen Sie nach der Sicherung einen Konvertierungsauftrag in der Oberfläche, läuft der Download ins Leere, und der Auftrag fehlt in der Datenbank. Nach dem Restore ist er wieder vorhanden, die JPG-Datei lässt sich erneut herunterladen, und das vorherige Anmelde-Cookie bleibt gültig, weil das `JWT_SECRET` unverändert ist. Wegen `AUTO_DELETE_EVERY_N_HOURS` enthält ein Backup ohnehin nur Dateien der letzten Stunden; wertvoll sind vor allem die Konten.

> **Prüfen:** `tar tzf` auf das Archiv listet `data/mydb.sqlite`, und nach dem Restore erscheinen die Konten wieder; Aufträge im Verlauf sind sichtbar, sofern sie noch nicht automatisch gelöscht waren.

## Schritt 7: Updates und Rollback

Release-Notes lesen, Backup wie in Schritt 6, dann nur `CONVERTX_TAG` in der `.env` ändern:

```bash
$ docker compose pull
$ docker compose up -d
$ docker compose logs --no-log-prefix | head -n 3
```

```bash
# alte Version erst nach erfolgreichem Test entfernen
```

```bash
$ docker rmi ghcr.io/c4illin/convertx:v0.19.0
```

Ein Rollback bedeutet: alten Tag eintragen, Datenordner aus dem Backup vor dem Update zurückspielen, neu starten. Nur den Tag zurückzudrehen ist riskant, denn ob eine ältere Version mit einer von der neueren Version veränderten Datenbank zurechtkommt, ist nicht dokumentiert. Wegen der Imagegröße von mehreren Gigabyte sollten Sie das alte Image nach einem erfolgreichen Update gezielt mit `docker rmi` entfernen, aber erst, wenn kein Rollback mehr nötig ist.

So läuft das Update, etwa von v0.19.0 auf v0.20.0: Nach dem Tagwechsel und `docker compose up -d` meldet das Log `ConvertX v0.20.0`, der Container wird nach wenigen Sekunden `healthy`, das vorhandene Konto meldet sich an, eine bestehende Sitzung bleibt gültig, ein falsches Passwort bekommt `403`, ein Aufruf ohne Anmeldung liefert `401`, und eine weitere Registrierung bleibt gesperrt.

> **Prüfen:** Die erste Logzeile nennt die neue Version, etwa `ConvertX v0.20.0`, und `docker compose ps` zeigt wieder `healthy`.

## Schritt 8: ConvertX entfernen

> **Warnung:** Die folgenden Befehle löschen alle Konten, Aufträge und Dateien unwiderruflich. Erstellen Sie vorher ein Backup, falls Sie die Daten noch brauchen.

```bash
$ cd /opt/convertx
$ docker compose down -v --remove-orphans
$ docker rmi ghcr.io/c4illin/convertx:v0.20.0
$ sudo rm -rf /opt/convertx
```

> **Prüfen:** `docker ps -a --filter name=convertx` und `docker images | grep convertx` liefern keine Ausgabe mehr.

Grundlagen zum Betrieb finden Sie in [Docker Compose unter Linux: Grundlage für Selfhosting](https://s-edv.com/anleitungen/docker-compose-linux-selfhosting-grundlage), [Docker Compose absichern: Secrets, Healthchecks, Non-Root](https://s-edv.com/anleitungen/docker-compose-absichern-secrets-healthchecks-non-root) und [Linux-Server absichern mit UFW und Fail2ban](https://s-edv.com/anleitungen/linux-server-absichern-ufw-fail2ban).

## Troubleshooting

**Login springt zurück auf die Login-Seite**

Zugriff per HTTP über Hostname oder IP. Das Cookie trägt das Attribut `Secure`. Prüfen mit `curl -sD - -o /dev/null -d 'email=...&password=...' http://host:3000/login | grep -i set-cookie`. Lösung: HTTPS per Reverse Proxy, im Notfall nur zum Ausprobieren `HTTP_ALLOWED=true`.

**Nach jedem Neustart abgemeldet**

`JWT_SECRET` fehlt oder ändert sich. Prüfen mit `docker compose exec convertx printenv JWT_SECRET`.

**`unable to open database file`**

Laut README stimmen dann die Rechte am Datenordner nicht. `PUID` und `PGID` an `id -u` und `id -g` anpassen oder den Ordner mit `chown` übergeben.

**`Bind for 127.0.0.1:3000 failed: port is already allocated`**

Der Port ist belegt. Mit `ss -ltnp | grep 3000` den Verursacher finden oder in der `compose.yaml` einen anderen Host-Port wählen.

**Pull findet das Image nicht**

Tag ohne „v“ angegeben. Die Registry kennt `0.19.0` nicht (Manifest-Abfrage mit HTTP 404), richtig ist `v0.19.0` bzw. `v0.20.0`.

**Ergebnisse verschwunden**

Die automatische Löschung nach `AUTO_DELETE_EVERY_N_HOURS` hat gegriffen; mit `0` abschaltbar.

## Häufige Fragen

### Ist ConvertX für personenbezogene Daten geeignet?

Besser als ein öffentlicher Online-Konverter, weil die Dateien Ihr Netz nicht verlassen. Trotzdem liegen sie unverschlüsselt auf dem Server. Begrenzen Sie die Speicherdauer über `AUTO_DELETE_EVERY_N_HOURS`, beschränken Sie den Serverzugang und nehmen Sie den Dienst in Ihr Verarbeitungsverzeichnis auf.

### Darf ConvertX ohne Anmeldung laufen?

Technisch ja, mit `ALLOW_UNAUTHENTICATED=true`. Die README warnt ausdrücklich davor, den Dienst so ins Internet zu stellen.

### Wie groß dürfen Dateien sein?

Die README nennt keine feste Obergrenze. Praktisch begrenzen Reverse Proxy, Plattenplatz und Rechenzeit. Mit `MAX_CONVERT_PROCESS` lässt sich die Zahl paralleler Konvertierungen begrenzen.

## Fazit

ConvertX ersetzt für typische Büroaufgaben die Online-Konverter, ohne dass Dateien das Unternehmen verlassen. Entscheidend sind ein festes `JWT_SECRET`, eine geschlossene Registrierung, HTTPS davor und ein Backup, das neben dem Datenordner auch die `.env` umfasst. Für automatisierte Dokumentenstrecken passt eine spezialisierte Lösung besser.

## Weiterführende Anleitungen und Quellen

- [Stirling PDF mit Docker einrichten](https://s-edv.com/anleitungen/stirling-pdf-werkzeugkasten-docker-einrichten): ergänzt ConvertX um PDF-Bearbeitung wie Zusammenführen, Schwärzen und Texterkennung.
- [Gotenberg als PDF-API mit Docker](https://s-edv.com/anleitungen/gotenberg-docker-pdf-api): die Alternative, wenn Dokumente automatisiert per API umgewandelt werden sollen.
- [Caddy als Reverse Proxy mit automatischem HTTPS](https://s-edv.com/anleitungen/caddy-reverse-proxy-automatisches-https-anleitung): für Schritt 5.
- [3-2-1-Backup-Strategie praktisch umsetzen](https://s-edv.com/anleitungen/3-2-1-backup-strategie-praktisch-umsetzen): damit das Archiv aus Schritt 6 nicht auf demselben Server liegt.
- [ConvertX auf GitHub mit README und Variablenübersicht](https://github.com/C4illin/ConvertX)
- [Release-Notes zu ConvertX v0.20.0](https://github.com/C4illin/ConvertX/releases/tag/v0.20.0)
- [Changelog des Projekts](https://github.com/C4illin/ConvertX/blob/main/CHANGELOG.md)
- [Container-Image in der GitHub Container Registry](https://github.com/C4illin/ConvertX/pkgs/container/ConvertX)
