Update README.md
This commit is contained in:
1 parent
8d7bc82fef
commit
0b52c0cde4
1 file changed
+578
@@ -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.
|
||||||
Reference in new issue
Block a user