Joplin mit Docker installieren: Quelloffene Notiz- und To-do-App mit selbst gehostetem Server
Joplin Server als Docker-Stack: So richten Sie die quelloffene Notiz-App mit PostgreSQL, Ende-zu-Ende-Verschlüsselung und Team-Sync auf Ihrem Linux-Server ein und ersetzen Evernote oder OneNote ohne Cloud-Abhängigkeit.
Werbung Mit * markierte Links sind Werbelinks: Bei einem Kauf erhalten wir eine Provision, der Preis bleibt gleich. Als Amazon-Partner verdiene ich an qualifizierten Verkäufen. Mehr dazu

Joplin ist eine quelloffene Notiz- und To-do-App mit Markdown, Notizbüchern und optionaler Ende-zu-Ende-Verschlüsselung (E2EE). Statt über Dropbox oder OneDrive synchronisieren die Clients mit dem selbst gehosteten Joplin Server: Notizen und Anhänge bleiben auf Ihrer Infrastruktur, Teams teilen Notizbücher, Drittanbieter entfallen. Für KMU ist das eine datenschutzfreundliche Alternative zu Evernote oder OneNote. Die Anleitung richtet Joplin Server mit Docker Compose auf einem 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), x86_64 oder ARM64, 1 bis 2 CPU-Kerne, mindestens 2 GB RAM, empfohlen 4 GB; mindestens 10 GB freier Speicher. Im Test belegten Joplin Server und PostgreSQL zusammen rund 420 MB RAM
- Docker Engine (mind. Version 20.10) und Docker Compose Plugin v2 installiert. Falls noch nicht vorhanden, folgen Sie 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
Legen Sie einen eigenen Ordner für alle Dateien des Stacks an; die Unterordner für PostgreSQL entstehen beim ersten Start.
# mkdir -p /opt/joplin
# cd /opt/joplinDas Verzeichnis existiert und ist leer:
# ls /opt/joplin# Erwartete Ausgabe: (leer)Schritt 2: .env-Datei mit Secrets anlegen
Die .env-Datei im Projektordner enthält Zugangsdaten und öffentliche Base-URL, wird von Docker Compose automatisch eingelesen und darf nicht in eine öffentliche Versionsverwaltung. Ersetzen Sie 192.168.1.100 durch IP oder Hostnamen Ihres Servers und wählen Sie 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änken Sie die Datei-Berechtigungen ein, damit nur der Eigentümer (hier root) sie lesen kann:
# chmod 600 /opt/joplin/.env# ls -la /opt/joplin/.env# Erwartete Ausgabe: -rw------- 1 root root ... /opt/joplin/.envSchritt 3: compose.yaml erstellen
Erstellen Sie /opt/joplin/compose.yaml. Der Stack besteht aus db (PostgreSQL 16) und app (Joplin Server); app startet erst nach bestandenem Datenbank-Healthcheck, was Verbindungsfehler beim ersten Start verhindert.
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; die App erreicht die DB intern über den Service-Namen
db. - Healthcheck + depends_on: Verhindert Race-Conditions beim ersten Start zuverlässig.
- Image-Tag
latest: Entspricht derzeit Version 3.7.2 (Stand September 2026). Für eine reproduzierbare Produktion schreiben Sie besser einen versionierten Tag fest, z. B.joplin/server:3.7.2.
Die YAML-Syntax ist fehlerfrei:
# docker compose -f /opt/joplin/compose.yaml config --quiet && echo "YAML OK"# Erwartete Ausgabe: YAML OKSchritt 4: Stack starten
Starten Sie den Stack aus dem Projektordner heraus. Docker Compose liest die .env-Datei automatisch ein:
# cd /opt/joplin
# docker compose up -dBeim ersten Start lädt Docker die Images (Joplin Server ab 3.7.2 ca. 190 MB, PostgreSQL ca. 400 MB) und richtet die Datenbank ein; das kann einige Minuten dauern.
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", dafür Zeilen wie:
# App: Starting server v3.7.2 (prod) on port 22300 ...Meldet das Log FATAL: password authentication failed, stimmen die Datenbankpasswörter in der .env nicht überein (Lösung unter Troubleshooting).
Schritt 5: Erst-Einrichtung im Browser
Öffnen Sie http://<SERVER-IP>:22300 und melden Sie sich im Web-Admin mit den Standard-Zugangsdaten an:
- E-Mail:
admin@localhost - Passwort:
admin
Ändern Sie sofort nach dem ersten Login E-Mail-Adresse und Passwort unter Admin > Users > admin. Das Standard-Passwort ist öffentlich bekannt.
Weitere Nutzer legen Sie ebenfalls unter Admin > Users an, jeweils mit eigener E-Mail-Adresse und Passwort für die Clients.
Der Status-Endpunkt antwortet. Verwenden Sie dieselbe Adresse wie in APP_BASE_URL; curl -I (HEAD-Anfrage) beantwortet Joplin Server grundsätzlich mit 400, daher ein normales GET:
# curl http://192.168.1.100:22300/api/ping# Erwartete Ausgabe:
# {"status":"ok","message":"Joplin Server is running"}Schritt 6: Joplin-Client verbinden
Im Joplin-Desktop-Client (Windows, macOS oder Linux) wählen Sie unter Werkzeuge > Einstellungen > Synchronisierung als Ziel Joplin Server und tragen 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
„Synchronisierung prüfen“ meldet eine erfolgreiche Verbindung; beim nächsten Sync werden alle Notizen übertragen.
Für Mobile-Clients (Android / iOS) ist der Weg identisch: Konfiguration > Synchronisierung > Joplin Server.
# docker compose logs app --tail=10# Nach dem ersten Client-Sync erscheinen Einträge wie:
# PUT /api/items/root:/... (200)Schritt 7: Ende-zu-Ende-Verschlüsselung aktivieren (optional)
E2EE ist rein clientseitig und unabhängig vom Sync-Ziel. Aktivieren Sie sie unter Werkzeuge > Einstellungen > Verschlüsselung; der Server sieht nur verschlüsselte Daten. Bewahren Sie das Schlüssel-Passwort sicher auf: Geht es verloren, sind alle Notizen unwiederbringlich verschlüsselt.
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 kein TLS. Für Internetzugriff ist ein Reverse-Proxy mit SSL-Zertifikat Pflicht, sonst gehen Anmeldedaten und Notizen unverschlüsselt über die Leitung. Eine Anleitung für Caddy mit automatischem Let's-Encrypt-Zertifikat: Caddy als Reverse Proxy einrichten. Binden Sie Port 22300 dann nur lokal ("127.0.0.1:22300:22300").
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 -d# curl https://joplin.example.com/api/ping# Erwartete Ausgabe: {"status":"ok","message":"Joplin Server is running"}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 -dErstellen Sie 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-*.sqlBeziehen Sie ./data/postgres zusätzlich ins Backup ein. Bind Mounts statt Named Volumes schützen vor docker compose down -v. Eine vollständige Strategie: 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: "App: Starting server v3.7.2 (prod) on port 22300"Eckdaten auf einen Blick
| Parameter | Wert |
|---|---|
| Image | joplin/server:latest (Stand September 2026: 3.7.2) |
| Begleit-Image | postgres:16 |
| Image-Größe | ca. 190 MB (3.7.2) |
| 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) und arm64 |
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
Ohne
depends_onmit Healthcheck startet die App vor PostgreSQL; die gezeigte Konfiguration verhindert das. Prüfen:docker compose logs dbmussdatabase system is ready to accept connectionszeigen.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
Fehlt
DB_CLIENToder ist falsch gesetzt, fällt Joplin auf SQLite zurück, ungeeignet für Multi-User und 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: Desktop (Windows, macOS, Linux), Mobile (Android, iOS) und Terminal-App. In den Sync-Einstellungen wählen Sie „Joplin Server“ und tragen APP_BASE_URL und Zugangsdaten ein.
Ist Ende-zu-Ende-Verschlüsselung (E2EE) mit dem selbst gehosteten Server möglich?
Ja. E2EE funktioniert clientseitig mit jedem Sync-Ziel; aktivieren Sie sie in jedem Client unter Einstellungen > Verschlüsselung. Der Server speichert dann nur verschlüsselte Daten.
Kann ich Notizbücher mit anderen Nutzern teilen?
Ja, das unterscheidet ihn von WebDAV- oder S3-Sync. Nach dem Anlegen weiterer Nutzer unter Admin > Users geben Sie im Desktop-Client Notizbücher per Share-Funktion frei; Änderungen synchronisieren in beide Richtungen.
Wie führe ich ein Update auf eine neue Version durch?
Mit docker compose pull && docker compose up -d; Datenbankmigrationen laufen beim Neustart automatisch. Erstellen Sie vorher unbedingt einen 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 kostenpflichtige Hosted-Service von Joplin-Entwickler Laurent Cozic, ohne eigene Infrastruktur, mit Daten beim Anbieter. Joplin Server ist das selbst gehostete Backend: volle Datenkontrolle, DSGVO-Konformität ohne Auftragsverarbeitungsvertrag mit einem Cloud-Anbieter, aber eigene Wartung und Backups.
Brauche ich den optionalen Transcribe-Service?
Nur für die automatische Texterkennung handschriftlicher Notizen (Bilder). joplin/transcribe:latest braucht bis zu 16 GB RAM und 4 CPUs; die hier gezeigte Konfiguration ohne Transcribe ist vollständig funktionsfähig.
Fazit
Joplin Server ist in unter 30 Minuten per Docker Compose installiert und dank PostgreSQL-Healthcheck und Bind-Mounts produktionstauglich. Wichtigster Schritt nach dem Start: das Standard-Passwort sofort ändern; außerhalb des lokalen Netzes gehört ein Reverse-Proxy mit HTTPS davor. Zur Container-Sicherheit: 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


