Joplin mit Docker installieren: Quelloffene Notiz- und To-do-App mit selbst gehostetem Server
Joplin Server als Docker-Stack: So richtest du die quelloffene Notiz-App mit PostgreSQL, Ende-zu-Ende-Verschlüsselung und Team-Sync DSGVO-konform auf deinem Linux-Server ein – Evernote oder OneNote ersetzen ohne Cloud-Abhängigkeit.

Joplin ist eine quelloffene Notiz- und To-do-App mit über 55.000 GitHub-Sternen, Markdown-Support, Notizbuch-Struktur und optionaler Ende-zu-Ende-Verschlüsselung (E2EE). Während Joplin-Clients standardmäßig über Cloud-Dienste wie Dropbox oder OneDrive synchronisieren, ermöglicht der selbst gehostete Joplin Server eine vollständige Datenkontrolle: Alle Notizen und Anhänge bleiben auf deiner Infrastruktur, Teams können Notizbücher gemeinsam nutzen, und du bist unabhängig von Drittanbietern. Besonders für KMU, die Evernote oder Microsoft OneNote durch eine DSGVO-konforme Lösung ersetzen wollen, ist das ein überzeugendes Argument. Diese Anleitung richtet den Joplin Server mit Docker Compose auf einem beliebigen Linux-Host ein – inklusive PostgreSQL, persistentem Storage und Web-Admin.
Voraussetzungen
- Linux-Host, VM oder NAS mit Docker-Unterstützung (Ubuntu 22.04/24.04 oder Debian empfohlen) – mindestens 2 GB RAM, empfohlen 4 GB; mindestens 10 GB freier Speicher
- Docker Engine (mind. Version 20.10) und Docker Compose Plugin v2 installiert – falls noch nicht vorhanden, folge der Anleitung Docker und Docker Compose auf Linux installieren
- Netzwerkzugriff auf Port 22300 des Hosts (oder Port 80/443 bei Reverse-Proxy)
- Für HTTPS-Betrieb: Domain oder DynDNS-Eintrag und ein Reverse-Proxy (Nginx, Traefik oder Caddy) – empfehlenswert für alles außerhalb des lokalen Netzes; eine Einführung bietet Caddy als Reverse Proxy einrichten
- Texteditor (nano, vim oder VS Code) für
compose.yamlund.env - Browser und
curlfür die Verifikation
Schritt 1: Projektordner anlegen
Lege einen eigenen Ordner für den Joplin-Stack an. Alle nachfolgenden Dateien kommen in dieses Verzeichnis. Die Unterordner für PostgreSQL-Daten werden beim ersten Start automatisch erstellt.
mkdir -p /opt/joplin
cd /opt/joplinVerifizieren: Das Verzeichnis existiert und ist leer:
ls /opt/joplin
# Erwartete Ausgabe: (leer)Schritt 2: .env-Datei mit Secrets anlegen
Lege eine .env-Datei im Projektordner an. Diese Datei enthält alle sensiblen Zugangsdaten und die öffentliche Base-URL. Sie wird von Docker Compose automatisch eingelesen und darf nicht ins öffentliche Versionsverwaltungssystem eingecheckt werden. Ersetze 192.168.1.100 durch die IP-Adresse oder den Hostnamen deines Servers und wähle ein sicheres Passwort.
# /opt/joplin/.env
# Öffentliche URL des Joplin Servers – EXAKT so, wie Clients ihn erreichen.
# Bei Reverse-Proxy mit HTTPS: https://joplin.example.com (kein trailing slash!)
APP_BASE_URL=http://192.168.1.100:22300
# PostgreSQL-Zugangsdaten (müssen in db- und app-Service identisch sein)
POSTGRES_USER=joplin
POSTGRES_PASSWORD=SicheresPasswortHier
POSTGRES_DATABASE=joplindbSchränke die Datei-Berechtigungen ein, damit nur root sie lesen kann:
chmod 600 /opt/joplin/.envVerifizieren:
ls -la /opt/joplin/.env
# Erwartete Ausgabe: -rw------- 1 root root ... /opt/joplin/.envSchritt 3: compose.yaml erstellen
Erstelle die Datei /opt/joplin/compose.yaml mit folgendem Inhalt. Der Stack besteht aus zwei Services: db (PostgreSQL 16) und app (Joplin Server). Der app-Container startet erst, wenn die Datenbank den Healthcheck bestanden hat – das verhindert Verbindungsfehler beim ersten Start.
services:
db:
image: postgres:16
container_name: joplin-db
restart: unless-stopped
volumes:
- ./data/postgres:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${POSTGRES_DATABASE}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DATABASE}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- joplin-net
app:
image: joplin/server:latest
container_name: joplin-app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
ports:
- "22300:22300"
environment:
APP_PORT: 22300
APP_BASE_URL: ${APP_BASE_URL}
DB_CLIENT: pg
POSTGRES_HOST: db
POSTGRES_PORT: 5432
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DATABASE: ${POSTGRES_DATABASE}
networks:
- joplin-net
networks:
joplin-net:
driver: bridgeWichtige Entscheidungen in dieser Konfiguration:
- PostgreSQL statt SQLite:
DB_CLIENT=pgaktiviert PostgreSQL, das für Multi-User-Betrieb zwingend nötig ist. SQLite ist nur für lokale Tests geeignet und bei Container-Neustart verlustgefährdet. - Kein Expose von Port 5432: Der Datenbank-Port wird bewusst nicht nach außen gemappt – der App-Container erreicht die DB intern über den Service-Namen
dbim selben Docker-Netzwerk. - Healthcheck + depends_on: Verhindert Race-Conditions beim ersten Start zuverlässig.
- Image-Tag
latest: Entspricht derzeit Version 3.7.1 (Mai 2026). Für eine reproduzierbare Produktion kannst du auf einen versionierten Tag pinnen, z. B.joplin/server:3.7.1.
Verifizieren: Die YAML-Syntax ist fehlerfrei:
docker compose -f /opt/joplin/compose.yaml config --quiet && echo "YAML OK"
# Erwartete Ausgabe: YAML OKSchritt 4: Stack starten
Starte den Stack aus dem Projektordner heraus. Docker Compose liest die .env-Datei automatisch ein:
cd /opt/joplin
docker compose up -dBeim allerersten Start lädt Docker die Images herunter (Joplin Server ca. 537 MB, PostgreSQL ca. 400 MB) und richtet die Datenbank ein. Das kann einige Minuten dauern.
Verifizieren: Beide Container laufen und der db-Container zeigt healthy:
docker compose ps
# Erwartete Ausgabe (gekürzt):
# NAME IMAGE STATUS
# joplin-db postgres:16 Up ... (healthy)
# joplin-app joplin/server:latest Up ...
docker compose logs app --tail=30
# Kein "error", kein "FATAL" – Zeilen wie:
# Joplin Server [info] App listening on port 22300Erscheint in den Logs ein Fehler wie FATAL: password authentication failed, stimmen die Datenbankpasswörter in der .env nicht überein – Stack stoppen, .env korrigieren, docker compose up -d erneut ausführen.
Schritt 5: Erst-Einrichtung im Browser
Öffne im Browser http://<SERVER-IP>:22300. Du siehst die Anmeldeseite des Joplin Web-Admin. Melde dich mit den Standard-Zugangsdaten an:
- E-Mail:
admin@localhost - Passwort:
admin
Ändere sofort nach dem ersten Login E-Mail-Adresse und Passwort unter Admin > Users > admin. Das Standard-Passwort ist öffentlich bekannt und darf in keiner produktiven Umgebung aktiv bleiben.
Weitere Nutzer kannst du ebenfalls unter Admin > Users anlegen. Jeder Nutzer erhält eine eigene E-Mail-Adresse und ein Passwort, mit dem er sich in den Joplin-Clients authentifiziert.
Verifizieren: Der HTTP-Endpunkt antwortet:
curl -I http://localhost:22300
# Erwartete Ausgabe:
# HTTP/1.1 200 OK (oder 302 Found bei Redirect zum Login)Schritt 6: Joplin-Client verbinden
Öffne einen Joplin-Desktop-Client (Windows, macOS oder Linux) und navigiere zu Werkzeuge > Einstellungen > Synchronisierung. Wähle als Synchronisierungsziel Joplin Server und trage folgende Werte ein:
- Joplin Server URL: den Wert aus
APP_BASE_URL, z. B.http://192.168.1.100:22300 - E-Mail: die gerade gesetzte Admin-E-Mail (oder ein neu angelegter Nutzer)
- Passwort: das geänderte Passwort
Klicke auf „Synchronisierung prüfen" – der Client meldet eine erfolgreiche Verbindung. Beim nächsten Sync werden alle Notizen auf den Server übertragen.
Für Mobile-Clients (Android / iOS) ist der Weg identisch: Konfiguration > Synchronisierung > Joplin Server.
Verifizieren:
docker compose logs app --tail=10
# Nach dem ersten Client-Sync erscheinen Einträge wie:
# GET /api/items/root:/... 200Schritt 7: Ende-zu-Ende-Verschlüsselung aktivieren (optional)
E2EE ist eine rein clientseitige Funktion und funktioniert unabhängig vom Sync-Ziel. Aktiviere sie im Desktop-Client unter Werkzeuge > Einstellungen > Verschlüsselung. Joplin verschlüsselt alle Notizen vor dem Upload; der Server selbst sieht nur verschlüsselte Daten. Das Schlüssel-Passwort muss an einem sicheren Ort aufbewahrt werden – geht es verloren, sind alle Notizen unwiederbringlich verschlüsselt.
Verifizieren: Im Client-Menü erscheint unter Verschlüsselung der Status „Aktiviert" und ein Verschlüsselungsschlüssel ist aufgelistet.
Schritt 8: HTTPS mit Reverse-Proxy (empfohlen für Internet-Betrieb)
Joplin Server terminiert selbst kein TLS. Für den Zugriff aus dem Internet ist ein Reverse-Proxy mit SSL-Zertifikat Pflicht – ohne HTTPS werden Anmeldedaten und Notizinhalte unverschlüsselt übertragen. Eine vollständige Anleitung für Caddy (automatisches Let's-Encrypt-Zertifikat) findest du unter Caddy als Reverse Proxy einrichten.
Wichtig: Nach dem Umstieg auf HTTPS muss APP_BASE_URL in der .env-Datei auf die HTTPS-URL aktualisiert werden:
APP_BASE_URL=https://joplin.example.comAnschließend Stack neu starten:
cd /opt/joplin
docker compose up -dVerifizieren:
curl -I https://joplin.example.com
# Erwartete Ausgabe: HTTP/2 200 (oder 302)Updates und Backups
Joplin Server führt Datenbankmigrationen beim Start automatisch durch. Ein Update läuft daher in zwei Befehlen:
cd /opt/joplin
docker compose pull && docker compose up -dErstelle vor jedem Update ein Datenbank-Backup:
# PostgreSQL-Dump
docker exec joplin-db pg_dump -U joplin joplindb > /opt/joplin/backup-$(date +%F).sql
# Backup prüfen
ls -lh /opt/joplin/backup-*.sqlDas ./data/postgres-Verzeichnis sollte zusätzlich in eine Backup-Strategie einbezogen werden – docker compose down -v würde Named Volumes löschen, daher werden hier Bind Mounts (Pfad-Volumes) verwendet. Eine vollständige Strategie beschreibt die Anleitung MySQL & PostgreSQL Backup automatisieren mit cron.
Verifizieren nach Update:
docker compose ps
# Beide Container Up/healthy, kein Restart-Loop
docker compose logs app --tail=20
# Keine Migrationsfehler; Zeile: "Joplin Server [info] App listening on port 22300"Eckdaten auf einen Blick
| Parameter | Wert |
|---|---|
| Image | joplin/server:latest (aktuell 3.7.1, Mai 2026) |
| Begleit-Image | postgres:16 |
| Image-Größe | ca. 537 MB |
| Port (App) | 22300 (HTTP, Web-UI + API) |
| Port (DB intern) | 5432 (nicht nach außen exponieren) |
| Volume (DB) | ./data/postgres:/var/lib/postgresql/data |
| Pflicht-Env | APP_BASE_URL, DB_CLIENT, POSTGRES_HOST, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DATABASE |
| Standard-Login | admin@localhost / admin (sofort ändern!) |
| Architektur | amd64 (x86_64); ARM64 vor Einsatz prüfen |
Troubleshooting / Typische Fehler
- „Invalid origin" im Client:
APP_BASE_URLstimmt nicht exakt mit der URL überein, die der Client verwendet. Häufige Ursachen:httpstatthttps, fehlender oder falscher Port, ein Trailing-Slash am Ende der URL. Lösung:.envanpassen, Stack neu starten. - App startet nicht / Verbindung zur DB schlägt fehl: Falls
depends_onmit Healthcheck fehlt, startet der App-Container bevor PostgreSQL bereit ist. Mit der gezeigten Konfiguration wird das verhindert. Prüfen:docker compose logs db– erscheintdatabase system is ready to accept connections? FATAL: password authentication failed for user "joplin":POSTGRES_PASSWORDin.envstimmt nicht mit dem beim DB-Init gesetzten Wert überein. Stack vollständig stoppen,./data/postgreslöschen (Datenverlust!),.envkorrigieren und neu starten.- Standard-Passwort vergessen zu ändern:
admin@localhost/adminsind öffentlich bekannt. Sofort nach dem ersten Login unter Admin > Users ändern. - Port 22300 bereits belegt: Fehlermeldung
Bind: address already in use. Prüfen mitss -tlnp | grep 22300, Prozess stoppen oder externen Port in dercompose.yamlanpassen (z. B.22301:22300). - SQLite statt PostgreSQL aktiv: Wenn
DB_CLIENTfehlt oder falsch gesetzt ist, fällt Joplin auf SQLite zurück. Nicht für Multi-User geeignet, und die Datei geht beidocker compose downverloren. Lösung:DB_CLIENT=pgplus allePOSTGRES_*-Variablen setzen. - Kein HTTPS im Internet-Betrieb: Ohne Reverse-Proxy mit TLS werden Anmeldedaten unverschlüsselt übertragen. Caddy, Nginx oder Traefik vorschalten;
APP_BASE_URLaufhttps://ändern.
Häufige Fragen
Welche Joplin-Clients können sich mit dem selbst gehosteten Server synchronisieren?
Alle offiziellen Clients unterstützen Joplin Server als Sync-Ziel: Desktop (Windows, macOS, Linux), Mobile (Android und iOS) sowie die Terminal-App. In den Sync-Einstellungen wählst du „Joplin Server" aus und trägst die APP_BASE_URL samt Zugangsdaten ein.
Ist Ende-zu-Ende-Verschlüsselung (E2EE) mit dem selbst gehosteten Server möglich?
Ja. E2EE ist eine clientseitige Funktion und funktioniert mit jedem Sync-Ziel – auch mit dem selbst gehosteten Server. Du aktivierst sie in jedem Client unter Einstellungen > Verschlüsselung. Der Server empfängt und speichert dann ausschließlich bereits verschlüsselte Daten und hat keinen Zugriff auf die Klartextinhalte.
Kann ich Notizbücher mit anderen Nutzern teilen?
Ja, das ist eine der Hauptfunktionen gegenüber WebDAV- oder S3-Sync. Im Web-Admin legst du unter Admin > Users weitere Nutzerkonten an. Im Desktop-Client kannst du anschließend ein Notizbuch über die Share-Funktion für andere Nutzer freigeben – änderungen werden bidirektional synchronisiert.
Wie führe ich ein Update auf eine neue Version durch?
Mit docker compose pull && docker compose up -d. Joplin Server führt ausstehende Datenbankmigrationen beim Neustart automatisch aus. Erstelle vorher unbedingt einen PostgreSQL-Dump mit docker exec joplin-db pg_dump -U joplin joplindb > backup.sql.
Was ist der Unterschied zwischen Joplin Server und Joplin Cloud?
Joplin Cloud ist der kommerzielle Hosted-Service von Laurent Cailleux (dem Joplin-Entwickler) – keine eigene Infrastruktur nötig, dafür monatliche Kosten und Datenspeicherung beim Anbieter. Joplin Server ist das selbst gehostete Backend: volle Datenkontrolle, DSGVO-Konformität ohne Auftragsverarbeitungsvertrag mit einem Cloud-Anbieter, aber eigenverantwortliche Wartung und Backups.
Brauche ich den optionalen Transcribe-Service?
Nur wenn du Sprachnotizen automatisch transkribieren möchtest. Der Service (joplin/transcribe:latest) benötigt bis zu 16 GB RAM und 4 CPUs und ist für die meisten Installationen nicht nötig. Die in dieser Anleitung gezeigte vereinfachte Konfiguration ohne Transcribe ist vollständig funktionsfähig.
Fazit
Joplin Server ist eine ausgereifte, aktiv gepflegte Lösung für Teams und Einzelpersonen, die ihre Notizen selbst hosten wollen. Die Docker-Compose-Installation ist in unter 30 Minuten abgeschlossen, und der Stack ist dank PostgreSQL-Healthcheck und Bind-Mounts produktionstauglich. Der wichtigste Schritt nach dem ersten Start: das Standard-Passwort sofort ändern. Wer den Server über das lokale Netz hinaus nutzen möchte, sollte einen Reverse-Proxy mit HTTPS vorschalten – Joplin selbst terminiert kein TLS. Für Container-Sicherheit im Allgemeinen lohnt sich ein Blick auf Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only.
Weiterführende Anleitungen und Quellen
- Docker und Docker Compose auf Linux installieren – die Self-Hosting-Grundlage
- Caddy als Reverse Proxy einrichten: Anfänger-Anleitung mit automatischem HTTPS
- MySQL & PostgreSQL Backup automatisieren mit cron
- Docker Compose absichern: Secrets, Healthchecks, Non-Root und Read-Only
Offizielle Quellen: Joplin Server README (GitHub) · Joplin Server auf Docker Hub · Joplin Server Changelog