OpenSign mit Docker installieren: Kostenlose DocuSign-Alternative für rechtssichere E-Signaturen
OpenSign ist die quelloffene Alternative zu DocuSign und Adobe Sign – mit kryptografischen Audit-Trails, Multi-Party-Workflows und Templates. Diese Anleitung zeigt, wie du den kompletten Stack per Docker Compose in 20 Minuten auf deinem eigenen Server deployst.

Wer regelmäßig Verträge, NDAs oder Angebote digital unterzeichnen lässt, kennt das Problem: DocuSign kostet ab 10 EUR pro Nutzer und Monat, Adobe Sign noch mehr – und beide schicken deine Dokumente durch externe US-Server. OpenSign löst dieses Problem vollständig: Die AGPL-3.0-lizenzierte Plattform bringt rechtssichere elektronische Signaturen, kryptografische Audit-Trails, Multi-Party-Workflows und wiederverwendbare Templates auf deinen eigenen Server. 6.500 GitHub-Sterne und über 50.000 Docker-Hub-Pulls je Image zeigen, dass die Lösung produktionsreif ist. Diese Anleitung richtet sich an KMU-Administratoren, Kanzleien und ambitionierte Selfhoster, die per docker compose up -d eine vollständige DocuSign-Alternative betreiben wollen – DSGVO-konform, ohne Cloud-Abhängigkeit, mit echtem ROI ab dem ersten unterzeichneten Vertrag.
Voraussetzungen
- Linux-Host, VM oder NAS mit Docker Engine und Docker Compose v2 (Plugin, nicht das veraltete
docker-composeBinary) – Installations-Grundlage: Docker und Docker Compose auf Linux installieren - Mindestens 2 GB RAM und 4 GB freier Speicherplatz (Frontend-Image 707 MB, Backend-Image 1,3 GB, MongoDB)
- Internetverbindung für den einmaligen Image-Download (ca. 2,5 GB gesamt)
- Optional: eigene Domain mit DNS-Verwaltungszugang (für HTTPS mit Let's Encrypt via Caddy); ohne Domain läuft alles unter
https://localhost:3001 - Optional: SMTP-Postfach oder Mailgun-Account für E-Mail-Benachrichtigungen (Signatur-Einladungen)
- Optional: kommerzielles AATL-Zertifikat (PFX/P12) für Adobe-Acrobat-vertrauenswürdige Signaturen
Schritt 1: Eckdaten und Stack-Überblick
Bevor du den Stack startest, hilft ein Blick auf die beteiligten Images, Ports und Volumes. So verstehst du, warum jede Konfigurationsentscheidung wichtig ist.
| Komponente | Image | Größe | Funktion |
|---|---|---|---|
| Frontend | opensign/opensign:main | 707 MB | React-UI, Signatur-Oberfläche |
| Backend | opensign/opensignserver:main | 1,3 GB | Node.js / Parse Server API |
| Datenbank | mongo:latest | ~700 MB | Dokumente, Nutzer, Audit-Trails |
| Reverse Proxy | caddy:latest | ~50 MB | Auto-TLS, HTTPS-Termination |
| Port (Host) | Container | Zweck | Öffentlich? |
|---|---|---|---|
| 3001 | Caddy | Haupt-Zugangspunkt HTTPS | Ja (über Caddy) |
| 80 / 443 | Caddy | HTTP-Redirect / HTTPS + HTTP/3 | Ja (Custom Domain) |
| 3000 | Frontend | React intern | Nur intern |
| 8080 | Backend | Node.js API | Niemals extern! |
| 27018 | MongoDB | DB-Zugriff (Host-Port) | Niemals extern! |
| Volume | Zweck | Kritisch? |
|---|---|---|
data-volume:/data/db | MongoDB-Daten (Dokumente, Signaturen) | Ja – ohne Volume Datenverlust! |
opensign-files:/usr/src/app/files | Lokaler PDF-Speicher (USE_LOCAL=true) | Ja |
caddy_data:/data | TLS-Zertifikate (Let's Encrypt) | Empfohlen |
caddy_config:/config | Caddy-interne Konfiguration | Empfohlen |
Verifizieren: Dieser Schritt erfordert keine Befehle. Merke dir: MongoDB-Port 27018 darf niemals in einer Firewall für das Internet geöffnet werden, da keine Authentifizierung konfiguriert ist.
Schritt 2: Projektordner anlegen und Konfigurationsdateien herunterladen
Lege einen dedizierten Ordner für den OpenSign-Stack an. Alle Konfigurationsdateien müssen sich im selben Verzeichnis befinden, weil Caddy die Caddyfile als relativen Bind-Mount einbindet.
mkdir -p /opt/opensign
cd /opt/opensign
# compose.yaml und Caddyfile aus dem offiziellen GitHub-Repo herunterladen
curl -fsSL https://raw.githubusercontent.com/OpenSignLabs/OpenSign/main/compose.yaml \
-o compose.yaml
curl -fsSL https://raw.githubusercontent.com/OpenSignLabs/OpenSign/main/Caddyfile \
-o CaddyfileVerifizieren:
ls -la /opt/opensign/
# Erwartet: compose.yaml Caddyfile (beide nicht leer)
wc -l compose.yaml
# Erwartet: mehr als 30 ZeilenFehlt die Caddyfile, startet Caddy zwar, aber OpenSign ist nicht erreichbar.
Schritt 3: Umgebungsvariablen konfigurieren (.env.prod)
Die gesamte Konfiguration – Secrets, URLs, E-Mail – landet in einer .env.prod-Datei. Ändere vor dem ersten Start unbedingt MASTER_KEY und PASS_PHRASE: Der Standard-MASTER_KEY (XnAadwKxxByMr) ist öffentlich bekannt und gibt vollen Datenbankzugriff.
Einen sicheren MASTER_KEY erzeugst du schnell per:
openssl rand -hex 20
# Ausgabe-Beispiel: a3f8c2d1e9b047561234abcd5678ef90abcd1234
# /opt/opensign/.env.prod
# =============================================
# PFLICHT-Einstellungen
# =============================================
# Öffentliche URL – bei Custom Domain anpassen (z. B. https://sign.example.com)
PUBLIC_URL=https://localhost:3001
# API-Endpunkt für das React-Frontend (intern – NICHT auf Public-URL ändern)
REACT_APP_SERVERURL=http://localhost:8080/app
# App-Identifier
REACT_APP_APPID=opensign
APP_ID=opensign
# MongoDB-Verbindung (Container-Name aus compose.yaml)
MONGODB_URI=mongodb://mongo-container:27017/OpenSignDB
# Interne API-URL
SERVER_URL=http://127.0.0.1:8080/app
# API-Mount-Pfad
PARSE_MOUNT=/app
# =============================================
# SECRETS – UNBEDINGT ÄNDERN!
# =============================================
MASTER_KEY=DEIN_SICHERER_MASTER_KEY_HIER
PASS_PHRASE=DEINE_SICHERE_PASSPHRASE_HIER
# =============================================
# Dateispeicher
# =============================================
USE_LOCAL=true
# =============================================
# E-Mail (optional, aber für Produktion nötig)
# =============================================
SMTP_ENABLE=false
SMTP_HOST=smtp.yourhost.com
SMTP_PORT=587
SMTP_USER_EMAIL=mailer@yourdomain.com
SMTP_PASS=SMTP_PASSWORT_HIER
# =============================================
# Performance
# =============================================
GENERATE_SOURCEMAP=falseVerifizieren:
grep "XnAadwKxxByMr" /opt/opensign/.env.prod
# Muss leer zurückkommen – sonst Standard-Secret noch aktiv!Schritt 4: compose.yaml prüfen und ggf. anpassen
Die heruntergeladene compose.yaml ist lauffähig und referenziert deine .env.prod per env_file-Direktive. Für Localhost-Betrieb sind keine weiteren Änderungen nötig. Bei Custom-Domain-Betrieb setzt du HOST_URL in einer zusätzlichen .env-Datei:
# Nur für Custom-Domain-Betrieb:
echo "HOST_URL=https://sign.example.com" > /opt/opensign/.envDie vollständige compose.yaml zur Referenz:
services:
mongo:
image: mongo:latest
container_name: mongo-container
restart: unless-stopped
volumes:
- data-volume:/data/db
ports:
- "27018:27017"
networks:
- app-network
server:
image: opensign/opensignserver:main
container_name: OpenSignServer-container
restart: unless-stopped
depends_on:
- mongo
volumes:
- opensign-files:/usr/src/app/files
ports:
- "8080:8080"
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
client:
image: opensign/opensign:main
container_name: OpenSign-container
restart: unless-stopped
depends_on:
- server
ports:
- "3000:3000"
env_file: .env.prod
networks:
- app-network
caddy:
image: caddy:latest
container_name: caddy-container
restart: unless-stopped
ports:
- "3001:3001"
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile
- 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:Wichtig: Das Image-Tag main ist kein stabiler Release-Tag und kann Breaking Changes enthalten. Für Produktivbetrieb empfiehlt sich ein versioniertes Tag (z. B. opensign/opensign:v2.39.0). Mehr zur Strategie in der Anleitung Docker-Container automatisch aktualisieren: Diun, WUD und Renovate im Vergleich.
Verifizieren:
docker compose -f /opt/opensign/compose.yaml config
# Muss die vollständige interpolierte Konfiguration ohne Fehler ausgebenSchritt 5: Stack starten und Images ziehen
Jetzt startest du alle vier Container. Beim ersten Start werden die Images heruntergeladen (ca. 2,5 GB); das kann einige Minuten dauern.
cd /opt/opensign
docker compose pull # Images vorab ziehen (empfohlen)
docker compose up -d # Alle Container im Hintergrund startenVerfolge den Start-Fortschritt mit:
docker compose logs -f server
# Warte auf: "Parse LiveQuery Server started" oder "Listening on port 8080"Verifizieren:
docker compose ps
# Erwartete Ausgabe (alle 4 Container "Up"):
# NAME IMAGE STATUS
# OpenSign-container opensign/opensign:main Up
# OpenSignServer-container opensign/opensignserver:main Up
# caddy-container caddy:latest Up
# mongo-container mongo:latest UpZeigt ein Container Restarting oder Exit, prüfe: docker compose logs server. Häufigste Ursache: falscher MASTER_KEY oder MONGODB_URI in der .env.prod.
Schritt 6: Erstzugang im Browser und Admin-Account anlegen
Öffne im Browser https://localhost:3001. Da Caddy bei Localhost-Betrieb ein selbstsigniertes Zertifikat verwendet, zeigt Chrome oder Firefox eine Sicherheitswarnung. Klicke auf „Erweitert" → „Weiter zu localhost" – das ist normal und einmalig nötig.
Auf der OpenSign-Startseite:
- Klicke auf „Sign Up" und lege deinen Admin-Account an.
- Bestätige die E-Mail-Adresse (nur wenn E-Mail-Versand konfiguriert ist; andernfalls direkt einloggen).
- Lade ein Test-PDF hoch, füge ein Signaturfeld hinzu und sende die Signaturanfrage an dich selbst.
- Überprüfe nach der Signatur, dass das fertige PDF einen Audit-Trail enthält (Download → PDF-Eigenschaften im Viewer).
Verifizieren:
# Erreichbarkeit prüfen (erwartet: HTTP/2 200 oder 302)
curl -k -I https://localhost:3001
# API-Endpunkt prüfen (erwartet: JSON-Antwort des Parse Servers)
curl -s http://localhost:8080/app/health | head -c 200Schritt 7: HTTPS mit eigener Domain einrichten (Caddy + Let's Encrypt)
Für Custom-Domain-Betrieb (z. B. sign.example.com) werden drei Voraussetzungen benötigt: DNS-A-Record auf die Server-IP, Ports 80 und 443 in der Firewall freigegeben, und HOST_URL gesetzt. Einen soliden Einstieg gibt es in der Anleitung Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS.
cd /opt/opensign
# HOST_URL setzen
echo "HOST_URL=https://sign.example.com" > .env
# PUBLIC_URL in .env.prod ebenfalls anpassen:
# PUBLIC_URL=https://sign.example.com
# (REACT_APP_SERVERURL bleibt auf http://localhost:8080/app – intern!)
docker compose down
docker compose up -dCaddy bezieht automatisch ein Let's-Encrypt-Zertifikat, sobald DNS korrekt gesetzt ist und Port 80/443 erreichbar sind.
Verifizieren:
curl -I https://sign.example.com
# Erwartet: HTTP/2 200, kein Zertifikatsfehler
docker compose logs caddy | grep -i "tls\|cert\|error"Schritt 8: E-Mail konfigurieren (SMTP oder Mailgun)
Ohne funktionierende E-Mail-Konfiguration startet OpenSign fehlerfrei – aber Unterzeichner erhalten nie eine Einladungs-E-Mail. Für Produktivbetrieb ist dieser Schritt unverzichtbar. Passe deine .env.prod an:
# Option A: SMTP (empfohlen für IONOS, Hetzner Mail, eigenen Postfix)
SMTP_ENABLE=true
SMTP_HOST=smtp.ionos.de
SMTP_PORT=587
SMTP_USER_EMAIL=noreply@example.com
SMTP_PASS=DEIN_SICHERES_SMTP_PASSWORT
# Option B: Mailgun
# SMTP_ENABLE=false
# MAILGUN_API_KEY=key-xxxxxxxxxxxxx
# MAILGUN_DOMAIN=mg.example.com
# MAILGUN_SENDER=noreply@example.comNach der Änderung an .env.prod die betroffenen Container neu starten:
cd /opt/opensign
docker compose up -d --force-recreate server clientHinweis zu Gmail: Gmail erfordert ein App-Passwort, kein normales Konto-Passwort. SMTP_PORT=587 mit STARTTLS ist der korrekte Wert. Der in einigen Quellen genannte Port 443 ist für SMTP unüblich – verwende immer den tatsächlichen Port deines Mail-Providers.
Verifizieren: Sende eine Test-Signaturanfrage an eine echte E-Mail-Adresse. Bei Problemen: docker compose logs server | grep -i "mail\|smtp\|error".
Schritt 9: Signaturzertifikat (PFX) einrichten
Für kryptografisch eingebettete PDF-Signaturen benötigst du ein PFX/P12-Zertifikat als Base64-Wert. Ein selbst erzeugtes Zertifikat reicht für interne Zwecke; für AATL-konforme Signaturen (Adobe Acrobat zeigt „vertrauenswürdig") ist ein kommerzielles Zertifikat nötig.
# Schlüssel und Zertifikat erzeugen
openssl genrsa -out private.key 2048
openssl req -new -key private.key -out cert.csr \
-subj "/CN=OpenSign/O=MeinUnternehmen/C=DE"
openssl x509 -req -days 3650 -in cert.csr \
-signkey private.key -out certificate.crt
# PFX-Datei erzeugen
openssl pkcs12 -export -out certificate.pfx \
-inkey private.key -in certificate.crt \
-passout pass:DEINE_PASSPHRASE
# Base64-Wert für .env.prod erzeugen
base64 -w 0 certificate.pfxDen Ausgabe-String in .env.prod eintragen:
PFX_BASE64=<langer-base64-string>
PASS_PHRASE=DEINE_PASSPHRASEVerifizieren: Nach docker compose up -d --force-recreate server prüfen: docker compose logs server | grep -i "pfx\|cert\|sign". Testdokument hochladen, signieren, Signatur-Badge im PDF-Viewer prüfen.
Schritt 10: Backup und Updates
Für eine solide Backup-Strategie empfiehlt sich die Anleitung 3-2-1-Backup-Strategie umsetzen: Anleitung mit Restic, USB-Disk und S3-Cloud. Für OpenSign konkret:
# MongoDB-Daten sichern (laufender Container)
docker exec mongo-container mongodump \
--db OpenSignDB \
--out /tmp/opensign-backup-$(date +%F)
docker cp mongo-container:/tmp/opensign-backup-$(date +%F) \
/opt/backups/opensign/
# Update einspielen
cd /opt/opensign
docker compose pull
docker compose up -dKritisch: Führe niemals docker compose down -v im Produktivbetrieb aus. Das Flag -v löscht alle benannten Volumes – Dokumente, Nutzer und Signaturen sind dann unwiederbringlich verloren.
Verifizieren: Nach dem Update prüft docker compose ps alle vier Container auf Status Up. Browser-Oberfläche öffnen und prüfen, dass bestehende Dokumente noch vorhanden sind.
Troubleshooting / Typische Fehler
- Container
serverstartet immer wieder neu (Restarting): Verbindungsfehler zur MongoDB. Prüfe:docker compose logs server | grep "MongoServerError\|ECONNREFUSED". Stelle sicher, dassMONGODB_URI=mongodb://mongo-container:27017/OpenSignDBkorrekt ist und der Container-Name übereinstimmt. - Browser-Warnung „Verbindung nicht sicher": Bei Localhost-Betrieb normal. Klicke auf „Erweitert" → „Weiter zu localhost (unsicher)". Das selbstsignierte Caddy-Zertifikat für Localhost löst diese Warnung immer aus – einmalig akzeptieren.
- Signaturanfragen kommen nie an: E-Mail nicht konfiguriert oder SMTP-Credentials falsch. Prüfe:
docker compose logs server | grep -i "mail\|smtp\|error". - Frontend zeigt „Cannot connect to server":
REACT_APP_SERVERURList auf einen externen URL gesetzt. Der interne Wert musshttp://localhost:8080/appbleiben. Externe URL nur fürSERVER_URLimserver-Container viaHOST_URLsetzen. - Caddy startet, aber Port 3001 nicht erreichbar:
Caddyfilefehlt oder liegt nicht im selben Verzeichnis wiecompose.yaml. Prüfe:docker compose logs caddy | grep -i "error\|caddyfile". - PDF-Signatur in Adobe Acrobat als „nicht vertrauenswürdig": Selbst generierte Zertifikate sind nicht in der Adobe Approved Trust List (AATL). Für AATL-Compliance ist ein kommerzielles Zertifikat nötig. Für interne Zwecke ist der Audit-Trail dennoch kryptografisch gültig.
- Breaking Changes nach
docker compose pull: Dasmain-Tag ist kein stabiler Release. Pinne auf versionierte Tags (z. B.v2.39.0) in dercompose.yamlund aktualisiere bewusst. - CORS-Fehler beim Hochladen (S3/DO Spaces): Nur bei
USE_LOCAL=false. Am Storage-Bucket eine CORS-Regel konfigurieren, die den OpenSign-Hostnamen als Origin erlaubt.
Häufige Fragen
Ist OpenSign DSGVO-konform?
Ja – beim Self-hosting bleiben alle Daten (Dokumente, Signaturen, personenbezogene Daten der Unterzeichner) ausschließlich auf deinem Server. Es werden keine Daten an externe Dienste übertragen, solange kein Cloud-Storage konfiguriert ist. Eine Datenschutzerklärung und Auftragsverarbeitungsverträge für E-Mail-Dienstleister sind dennoch erforderlich.
Kann ich OpenSign ohne eigene Domain lokal oder im Heimnetz betreiben?
Ja. Ohne HOST_URL ist die App unter https://localhost:3001 erreichbar. Für LAN-Zugriff setze HOST_URL=https://192.168.1.100 (eigene Server-IP) und akzeptiere das selbstsignierte Zertifikat im Browser einmalig. Eine öffentliche Domain ist nur für Let's-Encrypt-HTTPS zwingend nötig.
Wie erzeuge ich das PFX-Zertifikat für PFX_BASE64?
Schritt für Schritt per OpenSSL: (1) openssl genrsa -out private.key 2048, (2) openssl req -new -key private.key -out cert.csr, (3) openssl x509 -req -days 3650 -in cert.csr -signkey private.key -out certificate.crt, (4) openssl pkcs12 -export -out certificate.pfx -inkey private.key -in certificate.crt, (5) base64 -w 0 certificate.pfx liefert den Wert für PFX_BASE64. Das erzeugte Zertifikat ist nicht AATL-zertifiziert; für Acrobat-vertrauenswürdige Signaturen benötigst du ein kommerzielles Zertifikat.
Wie spiele ich Updates ein?
docker compose pull zieht neue Images; anschließend docker compose up -d startet die Container neu. MongoDB-Daten bleiben durch das persistente Volume erhalten. Erstelle vor jedem Update ein Mongodump-Backup und pin nach Möglichkeit auf versionierte Image-Tags.
Kann OpenSign eine externe MongoDB-Instanz verwenden?
Ja. Setze MONGODB_URI in .env.prod auf den externen Connection-String (z. B. mongodb+srv://user:pass@cluster.mongodb.net/OpenSignDB) und entferne den mongo-Service aus der compose.yaml.
Welche SMTP-Anbieter funktionieren?
Jeder SMTP-kompatible Anbieter: IONOS, Strato, Hetzner Mail, eigener Postfix-Server. Gmail erfordert ein App-Passwort. Port 587 mit STARTTLS ist der Standardwert; der in der offiziellen Vorlage gezeigte Port 443 ist unüblich – verwende immer den tatsächlichen Port deines Providers.
Sind die Signaturen eIDAS-konform?
OpenSign erzeugt elektronische Signaturen mit kryptografischem Audit-Trail, die als „einfache elektronische Signaturen" im Sinne der eIDAS-Verordnung gelten. Für den Großteil geschäftlicher Verträge (NDAs, Angebote, Dienstleistungsverträge) ist das rechtlich ausreichend. Für qualifizierte elektronische Signaturen (QES) – erforderlich z. B. für notarielle Akte – ist ein zugelassener Vertrauensdiensteanbieter nötig.
Fazit
OpenSign ist eine ausgereifte, produktionstaugliche Alternative zu DocuSign und Adobe Sign. Der Docker-Stack aus vier Containern ist in 20 Minuten betriebsbereit, und der ROI ist ab dem ersten Tag positiv – verglichen mit SaaS-Kosten ab 10 EUR pro Nutzer und Monat. Die wichtigsten Punkte für den sicheren Betrieb: MASTER_KEY vor dem ersten Start ändern, MongoDB-Port niemals ins Internet exponieren, das persistente Volume niemals mit -v löschen und E-Mail für Signatur-Einladungen konfigurieren. Wer auch Dokumentenverwaltung und OCR-Archivierung benötigt, findet in Paperless-ngx mit Docker einrichten die perfekte Ergänzung.
Weiterführende Anleitungen und Quellen
- Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
- Docker und Docker Compose auf Linux installieren (Ubuntu/Debian): die Self-Hosting-Grundlage
- Paperless-ngx mit Docker einrichten: papierlose Dokumentenverwaltung mit deutscher OCR
- Stirling-PDF mit Docker: der lokale PDF-Werkzeugkasten
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only für den Produktivbetrieb
Offizielle Quellen: OpenSign Self-Hosting-Dokumentation | OpenSign GitHub Repository | OpenSign ENV-Variablen-Referenz