---
title: "OpenSign mit Docker installieren: E-Signaturen selbst hosten"
date: 2026-06-26T06:32:32+02:00
modified: 2026-11-08T19:26:52+01:00
category: cloud
type: how_to
author: Marcel Schönfelder
canonical: https://s-edv.com/anleitungen/opensign-docker-esignatur
reading_time: 10
variables:
  - name: master_key
    label: "Schlüssel (master key)"
    generated_in_browser: true
  - name: pass_phrase
    label: "Passwort (pass phrase)"
    generated_in_browser: true
  - name: smtp_pass
    label: "Smtp pass"
    default: "IHR_SMTP_PASSWORT"
---

# OpenSign mit Docker installieren: E-Signaturen selbst hosten

## 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 |
| --- | --- | --- |
| `{{master_key}}` | Schlüssel (master key) | wird im Browser des Lesers zufällig erzeugt |
| `{{pass_phrase}}` | Passwort (pass phrase) | wird im Browser des Lesers zufällig erzeugt |
| `{{smtp_pass}}` | Smtp pass | `IHR_SMTP_PASSWORT` |

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.

**OpenSign** ist eine quelloffene Plattform für elektronische Signaturen (Lizenz AGPL-3.0) mit Audit-Trail, Workflows für mehrere Unterzeichner und Vorlagen. Selbst gehostet bleiben Dokumente und Unterzeichnerdaten auf Ihrem Server. Diese Anleitung richtet sich an Administratoren in KMU und Kanzleien und führt Sie vom Docker-Compose-Stack über HTTPS und E-Mail bis zu Signaturzertifikat, Backup und Updates.

**Kurzfassung:** OpenSign läuft als vier Container: React-Frontend, Node.js-Backend (Parse Server), MongoDB und Caddy als Reverse Proxy mit automatischem TLS. Sie laden `docker-compose.yml` und `Caddyfile` aus dem offiziellen Repository, legen eine `.env.prod` mit eigenem `MASTER_KEY` an, entfernen die Host-Ports von MongoDB, Backend und Frontend und starten mit `docker compose up -d`. Erreichbar ist OpenSign danach unter `https://localhost:3001` bzw. Ihrer Domain. Für den Betrieb brauchen Sie SMTP, feste Image-Versionen und ein Backup per `mongodump`.

## Voraussetzungen

- [ ] Linux-Server oder VM mit Docker Engine und dem Compose-Plugin v2, siehe [Docker und Docker Compose auf Linux installieren](https://s-edv.com/anleitungen/docker-compose-linux-selfhosting-grundlage)
- [ ] Mindestens **2 GB RAM** und **10 GB freier Speicher** für Images, Datenbank und Dokumente
- [ ] Für HTTPS mit Let's Encrypt: eigene Domain mit A-Record auf den Server, Ports 80 und 443 erreichbar
- [ ] SMTP-Postfach für Signatur-Einladungen
- [ ] **Linux-Kernel passend zu MongoDB 8.0:** Prüfen Sie mit `uname -r` die Kernel-Version des Hosts. Auf Ubuntu zeigt `uname -r` nur `7.0.0-…`, die zugrunde liegende Upstream-Version nennt `cat /proc/version_signature`. Unter 6.19 läuft `mongo:8.0` ohne Einschränkung. Von 6.19 bis 7.0.13 beendet sich MongoDB 8.0 beim Start mit „MongoDB cannot start: Linux kernel versions 6.19 and newer has a known incompatibility“ (SERVER-121912). Ab Kernel 7.0.14 beziehungsweise 7.1 startet MongoDB ab 8.0.30 wieder (Kompatibilitätstabelle in SERVER-125742). Ubuntu-Kernel der Reihe `7.0.0-…` erkennt die Startprüfung bis einschließlich 8.0.34 nicht als korrigiert (SERVER-136848), die Ausnahme ist laut SERVER-131779 in 8.0.35 enthalten. Auf einem betroffenen Host tragen Sie bei einer Neuinstallation in der `docker-compose.yml` `mongo:7.0` ein (Support laut MongoDB bis 31.08.2027). Vorhandene 8.0-Daten lassen sich nicht direkt mit 7.0 öffnen, weil MongoDB Community Edition kein Binär-Downgrade unterstützt.
- [ ] Optional: Signaturzertifikat im Format PFX/P12; für Signaturen, die Adobe Acrobat als vertrauenswürdig anzeigt, ein Zertifikat aus der Adobe Approved Trust List (AATL)

## Schritt 1: Eckdaten und Stack-Überblick

| Komponente | Image | Funktion |
| --- | --- | --- |
| Frontend | `opensign/opensign` | React-Oberfläche |
| Backend | `opensign/opensignserver` | Node.js / Parse Server API |
| Datenbank | `mongo:8.0` | Dokumente, Nutzer, Audit-Trails |
| Reverse Proxy | `caddy:2.11` | TLS, Weiterleitung an Frontend und `/api` |

| Port (Host) | Container | Zweck | Öffentlich? |
| --- | --- | --- | --- |
| 3001 | Caddy | Zugang ohne eigene Domain | Nur intern bzw. per Firewall begrenzt |
| 80 / 443 | Caddy | HTTP-Weiterleitung, HTTPS mit eigener Domain | Ja |
| 3000, 8080, 27017 | Frontend, Backend, MongoDB | nur im Docker-Netz | Nein, kein Host-Port |

| Volume | Zweck | Kritisch? |
| --- | --- | --- |
| `data-volume:/data/db` | MongoDB-Daten | Ja |
| `opensign-files:/usr/src/app/files` | PDF-Dateien bei `USE_LOCAL=true` | Ja |
| `caddy_data:/data` | TLS-Zertifikate | Empfohlen |
| `caddy_config:/config` | Caddy-Konfiguration | Empfohlen |

> **Prüfen:** `docker compose version` meldet Version 2.x. MongoDB läuft im Stack ohne Authentifizierung; ihr Port darf deshalb nie auf dem Host veröffentlicht werden.

## Schritt 2: Projektordner anlegen und Konfigurationsdateien herunterladen

`docker-compose.yml` und `Caddyfile` müssen im selben Verzeichnis liegen, weil Caddy die Datei relativ einbindet.

```bash
sudo mkdir -p /opt/opensign && cd /opt/opensign

sudo curl -fsSL -o docker-compose.yml \
  https://raw.githubusercontent.com/OpenSignLabs/OpenSign/main/docker-compose.yml
sudo curl -fsSL -o Caddyfile \
  https://raw.githubusercontent.com/OpenSignLabs/OpenSign/main/Caddyfile
```

> **Prüfen:** `ls -l /opt/opensign` zeigt beide Dateien mit einer Größe über 0 Byte; `head -3 Caddyfile` beginnt mit `{$HOST_URL} {`. Bricht `curl` mit 404 ab, hat sich der Dateiname im Repository geändert; prüfen Sie die aktuelle Self-Hosting-Dokumentation.

## Schritt 3: Umgebungsvariablen konfigurieren (.env.prod)

Secrets, URLs und E-Mail stehen in `.env.prod`. Die Beispielkonfiguration im Repository enthält einen öffentlich bekannten `MASTER_KEY` (`XnAadwKxxByMr`); er erlaubt vollen Zugriff auf die Parse-API. Erzeugen Sie eigene Werte:

```bash
$ openssl rand -hex 20   # fuer MASTER_KEY
$ openssl rand -hex 20   # fuer PASS_PHRASE
```

Legen Sie `/opt/opensign/.env.prod` an:

```bash
# Oeffentliche URL (bei eigener Domain: https://sign.example.com)
PUBLIC_URL=https://localhost:3001
APP_ID=opensign
REACT_APP_APPID=opensign

# MongoDB im Docker-Netz (Service-Name aus docker-compose.yml)
MONGODB_URI=mongodb://mongo:27017/OpenSignDB
SERVER_URL=http://127.0.0.1:8080/app
PARSE_MOUNT=/app

# Secrets: eigene Werte eintragen
MASTER_KEY={{master_key}}
PASS_PHRASE={{pass_phrase}}

USE_LOCAL=true
GENERATE_SOURCEMAP=false

# E-Mail (Schritt 8)
SMTP_ENABLE=false
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER_EMAIL=noreply@example.com
SMTP_PASS={{smtp_pass}}
```

```bash
$ sudo chmod 600 /opt/opensign/.env.prod
```

> **Prüfen:** `grep -c XnAadwKxxByMr /opt/opensign/.env.prod` gibt `0` aus.

## Schritt 4: docker-compose.yml prüfen und anpassen

Die Vorlage veröffentlicht MongoDB (27018), Backend (8080) und Frontend (3000) auf allen Host-Interfaces und nutzt die Tags `latest` bzw. `main`. Passen Sie die Datei so an: Host-Ports nur noch für Caddy, feste Versionen für MongoDB und Caddy, Neustart-Richtlinie für alle Dienste.

```yaml
services:
  server:
    image: opensign/opensignserver:main   # nach dem ersten Pull per Digest fixieren
    container_name: OpenSignServer-container
    restart: unless-stopped
    volumes:
      - opensign-files:/usr/src/app/files
    depends_on:
      - mongo
    env_file: .env.prod
    environment:
      - NODE_ENV=production
      - SERVER_URL=${HOST_URL:-https://localhost:3001}/api/app
      - PUBLIC_URL=${HOST_URL:-https://localhost:3001}
    networks:
      - app-network
  mongo:
    image: mongo:8.0
    container_name: mongo-container
    restart: unless-stopped
    volumes:
      - data-volume:/data/db
    networks:
      - app-network
  client:
    image: opensign/opensign:main         # nach dem ersten Pull per Digest fixieren
    container_name: OpenSign-container
    restart: unless-stopped
    depends_on:
      - server
    env_file: .env.prod
    networks:
      - app-network
  caddy:
    image: caddy:2.11
    container_name: caddy-container
    restart: unless-stopped
    ports:
      - "3001:3001"
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    environment:
      - HOST_URL=${HOST_URL:-localhost:3001}
    networks:
      - app-network
networks:
  app-network:
    driver: bridge
volumes:
  data-volume:
  opensign-files:
  caddy_data:
  caddy_config:
```

OpenSign veröffentlicht auf Docker Hub nur die Tags `main`, `staging` und `docker_beta`, keine Versionsnummern. Fixieren Sie deshalb nach dem ersten Pull den Digest: `docker image inspect --format '{{index .RepoDigests 0}}' opensign/opensign:main` liefert `opensign/opensign@sha256:…`; tragen Sie diesen Wert (ebenso für `opensignserver`) als `image:` ein. Updates übernehmen Sie dann bewusst, siehe [Docker-Container aktualisieren: Diun, WUD und Renovate](https://s-edv.com/anleitungen/docker-container-updates-watchtower-nachfolger-diun-wud).

> **Prüfen:** `docker compose config --quiet` endet ohne Ausgabe; `docker compose config | grep -A2 ports` zeigt Ports nur beim Dienst `caddy`.

## Schritt 5: Stack starten und Images ziehen

```bash
$ cd /opt/opensign
$ sudo docker compose pull
$ sudo docker compose up -d
$ sudo docker compose logs -f server   # Abbruch mit Strg+C
```

> **Prüfen:** `sudo docker compose ps` zeigt alle vier Container mit Status `Up`; `sudo ss -tlnp | grep -E ':(3000|8080|27017|27018)\b'` liefert keine Zeile. Zeigt ein Container `Restarting`, prüfen Sie `docker compose logs server`; häufige Ursache ist eine falsche `MONGODB_URI`.

## Schritt 6: Erstzugang im Browser und Admin-Account anlegen

Öffnen Sie `https://localhost:3001` (bzw. per SSH-Tunnel vom Arbeitsplatz). Caddy verwendet ohne Domain ein Zertifikat seiner lokalen CA; der Browser warnt deshalb einmalig.

1. Über „Sign Up“ das erste Konto anlegen; es wird Administrator.
2. Ein Test-PDF hochladen, ein Signaturfeld setzen und die Anfrage an sich selbst senden.
3. Nach der Signatur das fertige PDF herunterladen und den angehängten Audit-Trail prüfen.

> **Prüfen:** ```bash
> $ curl -k -s -o /dev/null -w '%{http_code}\n' https://localhost:3001            # 200
> $ curl -k -s https://localhost:3001/api/app/health                               # {"status":"ok"}
> ```

## Schritt 7: HTTPS mit eigener Domain einrichten (Caddy + Let's Encrypt)

Voraussetzungen: A-Record auf die Server-IP, Ports 80 und 443 offen. Grundlagen zu Caddy: [Caddy als Reverse Proxy mit automatischem HTTPS](https://s-edv.com/anleitungen/caddy-reverse-proxy-automatisches-https-anleitung).

```bash
$ cd /opt/opensign
$ echo "HOST_URL=https://sign.example.com" | sudo tee .env
$ sudo sed -i 's|^PUBLIC_URL=.*|PUBLIC_URL=https://sign.example.com|' .env.prod
$ sudo docker compose up -d --force-recreate
```

Mit eigener Domain entfernen Sie anschließend den Host-Port `3001` aus dem Dienst `caddy` oder sperren ihn in der Firewall.

> **Prüfen:** `curl -sI https://sign.example.com` liefert `HTTP/2 200` ohne Zertifikatsfehler; `docker compose logs caddy | grep -i "certificate obtained"` zeigt die Ausstellung.

## Schritt 8: E-Mail konfigurieren (SMTP oder Mailgun)

Ohne E-Mail startet OpenSign, Unterzeichner erhalten aber keine Einladung. Tragen Sie in `.env.prod` ein:

```bash
SMTP_ENABLE=true
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER_EMAIL=noreply@example.com
SMTP_PASS={{smtp_pass}}

# Alternativ Mailgun:
# MAILGUN_API_KEY=...
# MAILGUN_DOMAIN=mg.example.com
# MAILGUN_SENDER=noreply@example.com
```

```bash
$ sudo docker compose up -d --force-recreate server client
```

Verwenden Sie den Port Ihres Anbieters, meist 587 (STARTTLS); die Beispieldatei im Repository nennt 443, das ist für SMTP unüblich. Google-Konten verlangen ein App-Passwort.

> **Prüfen:** Eine Signaturanfrage an eine externe Adresse kommt an; bei Fehlern zeigt `docker compose logs server | grep -iE "mail|smtp"` die Ursache.

## Schritt 9: Signaturzertifikat (PFX) einrichten

OpenSign bettet die Signatur mit einem PFX-Zertifikat in das PDF ein. Ein selbst erzeugtes Zertifikat genügt für interne Zwecke; Adobe Acrobat zeigt es als „nicht vertrauenswürdig“ an.

```bash
openssl req -x509 -newkey rsa:3072 -nodes -days 1825 \
  -keyout private.key -out certificate.crt \
  -subj "/CN=OpenSign/O=Ihr Unternehmen/C=DE"
openssl pkcs12 -export -out certificate.pfx \
  -inkey private.key -in certificate.crt   # fragt die Export-Passphrase ab
base64 -w 0 certificate.pfx > certificate.b64
shred -u private.key
```

Tragen Sie in `.env.prod` `PFX_BASE64=` mit dem Inhalt von `certificate.b64` und als `PASS_PHRASE` die Export-Passphrase ein. Bewahren Sie `certificate.pfx` getrennt vom Server sicher auf.

> **Prüfen:** Nach `docker compose up -d --force-recreate server` ein Testdokument signieren; der PDF-Viewer zeigt im Signaturbereich das Zertifikat mit `CN=OpenSign`.

## Schritt 10: Backup und Updates

Sichern Sie Datenbank und Dateien, bevor Sie aktualisieren. Die übergeordnete Strategie beschreibt [3-2-1-Backup-Strategie praktisch umsetzen](https://s-edv.com/anleitungen/3-2-1-backup-strategie-praktisch-umsetzen).

```bash
cd /opt/opensign
D=$(date +%F)
sudo mkdir -p /opt/backups/opensign
sudo docker compose exec -T mongo mongodump --db OpenSignDB --archive --gzip \
  | sudo tee /opt/backups/opensign/opensign-$D.archive.gz >/dev/null
sudo docker run --rm -v opensign_opensign-files:/src:ro -v /opt/backups/opensign:/dst \
  alpine:3.22 tar czf /dst/files-$D.tar.gz -C /src .
```

Für ein Update tragen Sie neue Digests bzw. Versionen in `docker-compose.yml` ein und führen `sudo docker compose pull && sudo docker compose up -d` aus. Der Volume-Name `opensign_opensign-files` setzt den Projektordner `opensign` voraus; `docker volume ls` zeigt den tatsächlichen Namen.

> **Achtung:** `docker compose down -v` löscht alle benannten Volumes und damit sämtliche Dokumente und Signaturen.

> **Prüfen:** `gunzip -t /opt/backups/opensign/opensign-$D.archive.gz` meldet keinen Fehler; nach dem Update zeigt `docker compose ps` alle Container `Up` und bestehende Dokumente sind in der Oberfläche vorhanden.

## Troubleshooting / Typische Fehler

**Container `server` startet neu (`Restarting`)**

MongoDB nicht erreichbar. `docker compose logs server | grep -E "MongoServerError|ECONNREFUSED"`; `MONGODB_URI` muss auf den Service-Namen `mongo` zeigen.

**Browserwarnung bei localhost**

erwartet, weil Caddy ohne Domain ein Zertifikat seiner lokalen CA nutzt.

**Einladungen kommen nicht an**

SMTP-Daten oder Port falsch, siehe Schritt 8.

**Oberfläche meldet Verbindungsfehler zur API**

`HOST_URL` in `.env` und `PUBLIC_URL` in `.env.prod` stimmen nicht überein; beide auf dieselbe Adresse setzen und neu erstellen.

**Port 3001 nicht erreichbar**

`Caddyfile` fehlt im Projektordner. `docker compose logs caddy | grep -i caddyfile`.

**Acrobat zeigt „nicht vertrauenswürdig“**

Selbst erzeugte Zertifikate stehen nicht in der AATL; für externe Empfänger ein AATL-Zertifikat nutzen.

**Änderungen nach `docker compose pull`**

Das Tag `main` ändert sich mit jeder Veröffentlichung; per Digest fixieren (Schritt 4).

**CORS-Fehler beim Hochladen**

nur bei `USE_LOCAL=false` mit S3-kompatiblem Speicher; im Bucket eine CORS-Regel für Ihre OpenSign-Adresse anlegen.

## Häufige Fragen

### Ist OpenSign DSGVO-konform?

Selbst gehostet bleiben Dokumente und Unterzeichnerdaten auf Ihrem Server, solange Sie keinen externen Speicher konfigurieren. Die DSGVO-Pflichten als Verantwortlicher bleiben: Datenschutzhinweise für Unterzeichner, Löschkonzept und ein Auftragsverarbeitungsvertrag mit Ihrem Hoster und E-Mail-Dienstleister.

### Kann ich OpenSign ohne eigene Domain lokal oder im Heimnetz betreiben?

Ja, unter `https://localhost:3001` oder mit `HOST_URL=https://192.168.1.100:3001` für das LAN. Caddy stellt dann ein Zertifikat der lokalen CA aus. Für Let's Encrypt brauchen Sie eine öffentliche Domain.

### Wie erzeuge ich das PFX-Zertifikat für PFX_BASE64?

Mit den OpenSSL-Befehlen aus Schritt 9. Das Ergebnis ist selbst signiert und nicht AATL-zertifiziert.

### Wie spiele ich Updates ein?

Backup anlegen, neue Digests eintragen, `docker compose pull` und `docker compose up -d`. Die Volumes bleiben erhalten.

### Kann OpenSign eine externe MongoDB-Instanz verwenden?

Ja. Setzen Sie `MONGODB_URI` auf den externen Connection-String mit Benutzer und Passwort und entfernen Sie den Dienst `mongo` aus der Compose-Datei.

### Welche SMTP-Anbieter funktionieren?

Jeder Anbieter mit SMTP-Zugang. Nutzen Sie Port und Verschlüsselung laut Anbieter, meist 587 mit STARTTLS.

### Sind die Signaturen eIDAS-konform?

OpenSign erzeugt elektronische Signaturen im Sinne von Art. 3 Nr. 10 eIDAS-Verordnung, bei Einsatz eines Zertifikats unter Umständen fortgeschrittene Signaturen; qualifizierte elektronische Signaturen (QES) erzeugt es nicht. Wo das Gesetz Schriftform verlangt, ersetzt nur die QES sie (§ 126a BGB). Manche Erklärungen schließen die elektronische Form ganz aus, etwa die Kündigung eines Arbeitsverhältnisses (§ 623 BGB). Für Angebote, NDAs und viele Dienstleistungsverträge ohne Formvorschrift genügt eine einfache elektronische Signatur; klären Sie Zweifelsfälle rechtlich.

## Fazit

OpenSign lässt sich mit vier Containern in kurzer Zeit selbst betreiben. Für den sicheren Betrieb zählen: eigener `MASTER_KEY`, keine Host-Ports für MongoDB und Backend, feste Image-Digests, funktionierende E-Mail und regelmäßige Backups. Für die Ablage signierter Dokumente mit Volltextsuche ergänzt [Paperless-ngx mit Docker](https://s-edv.com/anleitungen/paperless-ngx-dokumentenverwaltung-ocr-docker) den Stack.

## Weiterführende Anleitungen und Quellen

1. [Caddy als Reverse Proxy mit automatischem HTTPS](https://s-edv.com/anleitungen/caddy-reverse-proxy-automatisches-https-anleitung)
2. [Docker und Docker Compose auf Linux installieren](https://s-edv.com/anleitungen/docker-compose-linux-selfhosting-grundlage)
3. [Paperless-ngx mit Docker einrichten](https://s-edv.com/anleitungen/paperless-ngx-dokumentenverwaltung-ocr-docker)
4. [Stirling-PDF mit Docker](https://s-edv.com/anleitungen/stirling-pdf-werkzeugkasten-docker-einrichten)
5. [Docker Compose absichern: Secrets, Healthchecks, Non-Root](https://s-edv.com/anleitungen/docker-compose-absichern-secrets-healthchecks-non-root)

Offizielle Quellen: [OpenSign Self-Hosting-Dokumentation](https://docs.opensignlabs.com/docs/self-host/docker/run-locally/) | [OpenSign auf GitHub](https://github.com/OpenSignLabs/OpenSign) | [OpenSign-Umgebungsvariablen](https://docs.opensignlabs.com/docs/self-host/guides/env-variables/) | [MongoDB SERVER-125742: Kernel-Kompatibilität](https://jira.mongodb.org/browse/SERVER-125742) | § 126a und § 623 BGB (gesetze-im-internet.de)

## Passende Beiträge auf S-EDV

1. [OpenSSL: neun Schwachstellen im Sicherheitsrelease vom 9. Juni 2026](https://s-edv.com/news/openssl-9-schwachstellen-juni-2026-patch-pkcs7)
2. [netcup Local Block Storage bestellen und unter Linux einbinden](https://s-edv.com/anleitungen/netcup-local-block-storage-bestellen-linux-einbinden)
3. [Linux-Kernel CVE-2026-23111: Fehler in nf_tables ermöglicht lokale Root-Rechte](https://s-edv.com/news/linux-kernel-cve-2026-23111-nftables-use-after-free-root-exploit)
