diff --git a/README.md b/README.md new file mode 100644 index 0000000..b0a8159 --- /dev/null +++ b/README.md @@ -0,0 +1,578 @@ +# 🌐 Joplin Web – Self-Hosted Docker + +Eine selbst gehostete **Joplin Web App**, die den offiziellen Joplin-Web-Client aus dem Joplin-Quellcode baut und anschließend über einen schlanken nginx-Container bereitstellt. + +Die Web-App kann mit einem vorhandenen **Joplin Server** synchronisiert werden und ermöglicht den Zugriff auf Joplin-Notizen direkt über den Browser. + +> ⚠️ Joplin Web befindet sich noch in Entwicklung/Beta. Vor produktivem Einsatz sollten Backups der Joplin-Daten vorhanden sein. + +--- + +## ✨ Features + +- 🌐 Joplin direkt im Webbrowser +- 🐳 Vollständig über Docker betreibbar +- 🔄 Synchronisation mit einem eigenen Joplin Server +- 🔐 Betrieb über HTTPS / Reverse Proxy +- 🗄️ Browserbasierter lokaler Speicher +- 📎 Unterstützung der Joplin-Synchronisation +- 🚀 Fertiges Docker-Image kann über eine Container Registry verteilt werden +- 🛡️ Zusätzlicher Zugriffsschutz über den Reverse Proxy möglich + +--- + +## 🏗️ Aufbau + +```text + ┌──────────────────────┐ + │ Browser │ + │ Firefox / Chrome ... │ + └──────────┬───────────┘ + │ + HTTPS + │ + ▼ + ┌──────────────────────┐ + │ Reverse Proxy │ + │ nginx / NPM / etc. │ + └──────────┬───────────┘ + │ + ▼ + ┌──────────────────────┐ + │ Joplin Web │ + │ nginx + Web App │ + │ Port 3000 │ + └──────────┬───────────┘ + │ + HTTPS / API + │ + ▼ + ┌──────────────────────┐ + │ Joplin Server │ + │ Sync + Benutzer │ + └──────────────────────┘ +``` + +--- + +# 📁 Projektstruktur + +```text +joplin-web/ +├── Dockerfile +├── docker-compose.yml +├── nginx.conf +├── README.md +└── .gitignore +``` + +--- + +# 🚀 Installation + +## Variante 1 – Fertiges Container-Image + +Wenn das Image bereits in einer Container Registry vorhanden ist, wird auf dem Zielserver kein Joplin-Build benötigt. + +Beispiel: + +```yaml +services: + joplin-web: + image: gitea.example.com/username/joplin-web:latest + container_name: joplin-web + restart: unless-stopped + + ports: + - "3000:80" + + security_opt: + - no-new-privileges:true +``` + +Container starten: + +```bash +docker compose pull +docker compose up -d +``` + +Status prüfen: + +```bash +docker compose ps +``` + +Logs anzeigen: + +```bash +docker logs -f joplin-web +``` + +Die Web-App ist anschließend lokal unter folgendem Port erreichbar: + +```text +http://SERVER-IP:3000 +``` + +> Für den produktiven Betrieb sollte Joplin Web über **HTTPS** bereitgestellt werden. + +--- + +# 🔨 Variante 2 – Image selbst bauen + +Repository klonen: + +```bash +git clone https://gitea.example.com/username/joplin-web.git +cd joplin-web +``` + +Image bauen: + +```bash +docker compose build --no-cache --progress=plain +``` + +Anschließend starten: + +```bash +docker compose up -d +``` + +Status prüfen: + +```bash +docker compose ps +``` + +--- + +# 🐳 Docker Image + +Das Docker-Image wird in mehreren Stufen gebaut. + +## Builder + +Im ersten Schritt wird der offizielle Joplin-Quellcode geladen und die Web-App gebaut. + +Dabei werden unter anderem verwendet: + +- Devbox +- Nix +- Node.js +- Yarn +- Joplin Source +- Joplin Mobile Web Build + +Der Web-Build wird anschließend aus folgendem Verzeichnis übernommen: + +```text +packages/app-mobile/web/dist +``` + +## Runtime + +Der eigentliche produktive Container benötigt die Build-Umgebung nicht mehr. + +Das fertige Web-Frontend wird über: + +```text +nginx +``` + +bereitgestellt. + +Dadurch bleibt der laufende Container wesentlich kleiner als die Build-Umgebung. + +--- + +# 🔐 HTTPS + +Joplin Web sollte nicht dauerhaft über eine unverschlüsselte HTTP-Verbindung verwendet werden. + +Bestimmte Browser-APIs, die Joplin Web benötigt, stehen nur in einem **Secure Context** zur Verfügung. + +Empfohlen: + +```text +https://joplin-web.example.com +``` + +Der Reverse Proxy kann intern weiterhin auf: + +```text +http://JOPLIN-WEB-IP:3000 +``` + +weiterleiten. + +--- + +# 🧠 Cross-Origin Isolation + +Für bestimmte Browser-Funktionen werden folgende HTTP-Header ausgeliefert: + +```text +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: same-origin +``` + +Überprüfen: + +```bash +curl -I http://127.0.0.1:3000 +``` + +Beispiel: + +```text +HTTP/1.1 200 OK +Server: nginx + +Cross-Origin-Opener-Policy: same-origin +Cross-Origin-Embedder-Policy: require-corp +Cross-Origin-Resource-Policy: same-origin +``` + +Im Browser kann zusätzlich geprüft werden: + +```javascript +window.isSecureContext +``` + +und: + +```javascript +crossOriginIsolated +``` + +--- + +# 🔄 Verbindung mit Joplin Server + +In Joplin Web unter der Synchronisationskonfiguration als Ziel **Joplin Server** auswählen. + +Als Server-URL wird ausschließlich die Basis-URL verwendet: + +```text +https://joplin.example.com +``` + +Nicht: + +```text +https://joplin.example.com/api +``` + +und nicht: + +```text +https://joplin.example.com/login +``` + +Anschließend die Zugangsdaten des Joplin-Benutzers eintragen. + +--- + +# 🌍 CORS bei eigenem Joplin Server + +Wenn Joplin Web und Joplin Server unterschiedliche Domains verwenden, muss der Browser Cross-Origin-Anfragen zulassen. + +Beispiel: + +```text +Joplin Web: +https://joplin-web.example.com + +Joplin Server: +https://joplin.example.com +``` + +Ohne entsprechende Konfiguration können Fehler auftreten wie: + +```text +Blocked by CORS policy +``` + +oder: + +```text +Cross-Origin Request Blocked +``` + +## Beispiel für nginx / Nginx Proxy Manager + +Auf dem Reverse Proxy des **Joplin Servers**: + +```nginx +proxy_hide_header Access-Control-Allow-Origin; +proxy_hide_header Access-Control-Allow-Methods; +proxy_hide_header Access-Control-Allow-Headers; + +more_set_headers "Access-Control-Allow-Origin: https://joplin-web.example.com"; +more_set_headers "Access-Control-Allow-Methods: GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS"; +more_set_headers "Access-Control-Allow-Headers: Content-Type, Authorization, X-API-MIN-VERSION, X-API-AUTH"; +more_set_headers "Vary: Origin"; +``` + +> Die Domain muss an die eigene Joplin-Web-Adresse angepasst werden. + +--- + +## CORS testen + +Preflight-Anfrage: + +```bash +curl -i -X OPTIONS \ + -H "Origin: https://joplin-web.example.com" \ + -H "Access-Control-Request-Method: PUT" \ + -H "Access-Control-Request-Headers: content-type,x-api-min-version,x-api-auth" \ + https://joplin.example.com/api/items/root:/testing.txt:/content +``` + +Die Antwort sollte unter anderem enthalten: + +```text +Access-Control-Allow-Origin: https://joplin-web.example.com + +Access-Control-Allow-Methods: +GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS + +Access-Control-Allow-Headers: +Content-Type, Authorization, X-API-MIN-VERSION, X-API-AUTH +``` + +--- + +# 🔒 Zusätzlicher Zugriffsschutz + +Da die Web-App grundsätzlich über ihre URL erreichbar ist, empfiehlt sich ein zusätzlicher Schutz auf Reverse-Proxy-Ebene. + +Mögliche Lösungen: + +- HTTP Basic Authentication +- Nginx Proxy Manager Access Lists +- Authelia +- Authentik +- VPN / WireGuard / NetBird + +Die Architektur sieht dann beispielsweise so aus: + +```text +Internet + │ + ▼ +Reverse Proxy + │ + ├── Authentifizierung + │ + ▼ +Joplin Web + │ + ▼ +Joplin Server +``` + +Die eigentlichen Joplin-Zugangsdaten werden weiterhin für die Synchronisation mit dem Joplin Server verwendet. + +--- + +# 🔄 Update + +## Bei Verwendung eines fertigen Images + +```bash +docker compose pull +docker compose up -d +``` + +Nicht mehr verwendete Images können anschließend entfernt werden: + +```bash +docker image prune +``` + +--- + +## Bei lokalem Build + +Repository aktualisieren: + +```bash +git pull +``` + +Danach neu bauen: + +```bash +docker compose build --no-cache +docker compose up -d +``` + +--- + +# 📦 Image in eine Gitea Container Registry pushen + +Zunächst anmelden: + +```bash +docker login gitea.example.com +``` + +Image taggen: + +```bash +docker tag joplin-web-joplin-web:latest \ + gitea.example.com/username/joplin-web:latest +``` + +Danach: + +```bash +docker push gitea.example.com/username/joplin-web:latest +``` + +Auf einem anderen Docker-Server genügt anschließend: + +```bash +docker login gitea.example.com +docker compose pull +docker compose up -d +``` + +Damit muss Joplin auf dem Zielserver **nicht erneut aus dem Quellcode gebaut werden**. + +--- + +# 🧹 Nützliche Docker-Befehle + +Container anzeigen: + +```bash +docker compose ps +``` + +Logs: + +```bash +docker logs -f joplin-web +``` + +Container neu starten: + +```bash +docker compose restart +``` + +Container stoppen: + +```bash +docker compose down +``` + +Container starten: + +```bash +docker compose up -d +``` + +Image neu bauen: + +```bash +docker compose build --no-cache +``` + +--- + +# 🛠️ Fehlerbehebung + +## Web-App lädt nicht + +Container prüfen: + +```bash +docker compose ps +``` + +Logs: + +```bash +docker logs joplin-web --tail 100 +``` + +Webserver lokal testen: + +```bash +curl -I http://127.0.0.1:3000 +``` + +--- + +## Synchronisation schlägt fehl + +Browser-Entwicklertools öffnen und unter **Console** bzw. **Network** nach Fehlern suchen. + +Häufige Ursachen: + +- falsche Joplin-Server-URL +- CORS +- fehlender `X-API-AUTH` Header +- Reverse-Proxy-Konfiguration +- Zertifikatsprobleme + +--- + +## Browser zeigt alten Stand + +Joplin Web verwendet Browser-Speicher und Service Worker. + +Bei Problemen: + +1. Alle Joplin-Web-Tabs schließen. +2. Website-Daten der Joplin-Web-Domain löschen. +3. Browser vollständig schließen. +4. Browser neu starten. +5. Joplin Web erneut öffnen. + +--- + +# ⚠️ Hinweise + +Joplin Web speichert lokale Client-Daten im Browser. + +Daher gilt: + +- Browserdaten nicht unüberlegt löschen. +- Synchronisation vor größeren Änderungen vollständig durchführen. +- Regelmäßige Backups des Joplin Servers erstellen. +- Die Web-App möglichst nur über HTTPS betreiben. +- Für öffentlich erreichbare Installationen zusätzlichen Zugriffsschutz verwenden. + +--- + +# 🔗 Links + +- Joplin: https://joplinapp.org/ +- Joplin GitHub: https://github.com/laurent22/joplin +- Joplin Build Documentation: https://joplinapp.org/help/dev/BUILD/ +- Docker: https://www.docker.com/ +- Gitea: https://about.gitea.com/ + +--- + +# 📜 Lizenz + +Dieses Repository enthält die Docker-/Deployment-Konfiguration für Joplin Web. + +Joplin selbst ist ein eigenständiges Open-Source-Projekt. Für Joplin gelten die Lizenzbedingungen des offiziellen Joplin-Projekts. + +--- + +## ❤️ Credits + +[Joplin](https://joplinapp.org/) wird von Laurent Cozic und der Joplin-Community entwickelt. + +Dieses Repository stellt lediglich eine Docker-basierte Möglichkeit bereit, den Joplin-Web-Client selbst zu bauen und zu hosten.