diff --git a/README.md b/README.md index f355188..43a7d14 100644 --- a/README.md +++ b/README.md @@ -520,9 +520,14 @@ entsteht der Container dann nie, ohne jede Fehlermeldung. image: collabora/code:latest restart: unless-stopped environment: - # Wer seine Dateien hier öffnen darf. Punkte maskieren – Collabora liest - # den Wert als regulären Ausdruck. - aliasgroup1: http://app:8080 + # Wer seine Dateien hier öffnen darf – **die Adresse, unter der dein + # Browser die Cloud sieht**, nicht der interne Dienstname. Collabora + # liest den Wert als regulären Ausdruck, Punkte müssen also maskiert + # werden, und der Port gehört dazu (443 bei HTTPS). + # + # Steht hier der falsche Wert, meldet das Log beim Öffnen: + # No authorized hosts found matching the target host […] in config + aliasgroup1: https://cloud\.example\.com:443 # ssl.enable – spricht Collabora selbst HTTPS? # ssl.termination – endet HTTPS davor, an deinem Reverse Proxy? # Steht termination auf true ohne HTTPS davor, verlangt Collabora eine @@ -543,10 +548,34 @@ entsteht der Container dann nie, ohne jede Fehlermeldung. OFFICE_PROVIDER=collabora OFFICE_URL=http://office:9980 OFFICE_PUBLIC_URL=https://office.example.com -OFFICE_WOPI_URL=http://app:8080 +# **Öffentliche Adresse, nicht app:8080** – Begründung direkt darunter. +OFFICE_WOPI_URL=https://cloud.example.com OFFICE_ALLOWED_HOSTS=office ``` +> **Warum bei Collabora die öffentliche Adresse und nicht `app:8080`?** +> +> Weil Collabora aus dieser Adresse seine eigene Sicherheitsrichtlinie baut. +> Gemessen: Es setzt `frame-ancestors` auf *seinen* Host **plus den Host aus +> `WOPISrc`* – und `WOPISrc` ist genau `OFFICE_WOPI_URL`. Steht dort der +> interne Dienstname, erlaubt der Editor die Einbettung nur einer Seite, die +> unter `app:8080` läuft. Dein Browser kommt aber von `cloud.example.com`, und +> er lehnt ab: +> +> ``` +> Framing 'https://office.example.com/' violates +> 'frame-ancestors office.example.com:* app:8080' +> ``` +> +> Die Folge davon muss man wollen: Collabora holt die Datei dann **über deinen +> Reverse Proxy**, nicht quer durchs Docker-Netz. Der Container braucht dafür +> Namensauflösung nach draußen und einen Weg zurück – bei einem Proxy auf +> einem anderen Rechner ist das der normale Weg über das Internet. +> +> `aliasgroup1` oben muss **denselben** Host nennen. Zwei Schalter, eine +> Wahrheit: Der eine entscheidet, ob der Browser den Rahmen zeigen darf, der +> andere, ob Collabora die Anfrage überhaupt annimmt. + ### Schnipsel 2: OnlyOffice Docs ```yaml @@ -598,10 +627,14 @@ heißen gleich. Für uns ist es deshalb **derselbe Anbieter** – Die `.env` ist dieselbe wie bei OnlyOffice. Rechne mit **5 GB** allein für das Abbild. -> **Ungeprüft.** Collabora ist hier gemessen worden, den Kreis von Tippen bis -> Speichern eingeschlossen. Die beiden anderen Schnipsel stehen nach ihrer -> Dokumentation und dem gemeinsamen WOPI-Weg, sind auf dieser Anlage aber nie -> gelaufen – für OnlyOffice fehlt schlicht der Arbeitsspeicher. +> **Teilweise geprüft.** Collabora ist hier gemessen worden, den Kreis von +> Tippen bis Speichern eingeschlossen. OnlyOffice lief inzwischen auf dieser +> Anlage – gemessen sind sein Start, die Umwandlung nach PDF und die +> JWT-Signatur (ohne Signatur antwortet es mit `{"error":-8}`); im Leerlauf +> braucht es 396 MB, nach jedem Start belegt es für einige Minuten einen Kern, +> weil es seine eigenen Web-Dateien packt. **Nicht** gemessen ist dort der +> WOPI-Kreis vom Tippen bis zum Speichern. Euro-Office steht nach der +> Dokumentation und dem gemeinsamen Weg, ist hier nie gelaufen. > > Wenn der Editor dort leer bleibt, sind das die zwei Stellen, an denen es > nach Aktenlage hakt: @@ -614,9 +647,12 @@ Abbild. > Signatur **nicht** – erlaubt, aber falls es dort eine Pflicht gibt, wäre > das der Ort. > -> `JWT_SECRET` betrifft nach der Dokumentation die eigene API des -> Dokumentenservers, nicht den WOPI-Weg – unser Adapter signiert damit nichts. -> Der Schlüssel gehört trotzdem gesetzt, sonst läuft der Server offen. +> `JWT_SECRET` betrifft die eigene API des Dokumentenservers, nicht den +> WOPI-Weg – unser Adapter signiert damit nichts. Nachgemessen: `POST +> /ConvertService.ashx` ohne Signatur antwortet `{"error":-8}`, mit Signatur +> (HS256, entweder als Feld `token` im Rumpf oder als `Authorization: Bearer` +> über `{"payload": …}`) kommt das Ergebnis. Der Schlüssel gehört also +> gesetzt – sonst läuft die API offen. ### Welche Dateien, und wie gut @@ -671,6 +707,8 @@ Alles hier ist beim Testen tatsächlich passiert, in dieser Reihenfolge: | Rahmen bleibt leer, Konsole: *„Framing … violates default-src 'self'"* | Unsere eigene Sicherheitsrichtlinie. `frame-src` fällt auf `default-src` zurück; der Office-Ursprung muss ausdrücklich erlaubt sein. Passiert automatisch, sobald `OFFICE_PROVIDER` gesetzt ist. | | Editor lädt, Dokument bleibt weiß | `ssl.termination=true` ohne HTTPS davor. Collabora sagt dem Browser dann `wss://`, das es nicht gibt. Im HTTP-Test `OFFICE_SSL_TERMINATION=false`. | | Log: *„CheckFileInfo returned 0 … ECONNREFUSED"* | `OFFICE_WOPI_URL` zeigt auf `127.0.0.1:8090`. Der Port ist auf loopback gebunden – aus einem Container nicht erreichbar. Im Compose den Dienstnamen nehmen. | +| Konsole: *„Framing … violates 'frame-ancestors … app:8080'"* | `OFFICE_WOPI_URL` steht auf dem internen Dienstnamen. Collabora baut daraus seine Richtlinie und erlaubt dann nur eine Einbettung von dort. Die öffentliche Adresse der Cloud eintragen. | +| Log: *„No authorized hosts found matching the target host …"* | `aliasgroup1` kennt diesen Host nicht. Öffentliche Adresse eintragen, Punkte maskieren, Port anhängen – und den **Office**-Container neu erzeugen, nicht nur die App. Prüfen mit `docker compose logs office \| grep "trusted WOPI host"`. | | Log: *„WOPISrc must be URI-encoded"* | Behoben; die Adresse wird vollständig kodiert. | | Log: *„Failed to exec coolmount … needs CAP_SYS_ADMIN"* | Gelöst über `--o:mount_jail_tree=false` im Compose. | | Fehlende Symbole (404 auf `.svg`) | Lücken im Collabora-Image selbst. Kosmetisch. | diff --git a/deploy/.env.example b/deploy/.env.example index 71d04ed..c42b8d1 100644 --- a/deploy/.env.example +++ b/deploy/.env.example @@ -102,6 +102,9 @@ OFFICE_URL= OFFICE_PUBLIC_URL= # Office → Aether; leer = PUBLIC_URL. # Weder localhost noch der veröffentlichte Port – beides scheitert. +# **Bei Collabora die öffentliche Adresse der Cloud**, nicht app:8080: Aus +# diesem Wert baut Collabora sein frame-ancestors, und der Browser darf den +# Rahmen sonst nicht zeigen. Siehe README, Abschnitt Office. OFFICE_WOPI_URL= # Gegen SSRF; der Host aus OFFICE_URL zählt immer dazu. OFFICE_ALLOWED_HOSTS= @@ -109,7 +112,11 @@ OFFICE_ALLOWED_HOSTS= OFFICE_JWT_SECRET= OFFICE_INSECURE_TLS=false # nur für Tests mit selbstsigniertem Zertifikat -# Nur für den Collabora-Container aus deploy/docker-compose.yml: +# Nur für den Collabora-Container aus deploy/docker-compose.yml. +# Derselbe Host wie in OFFICE_WOPI_URL, aber als regulärer Ausdruck: Punkte +# maskieren, Port anhängen. Beispiel: +# OFFICE_ALIASGROUP=https://cloud\.example\.com:443 +# Fehlt er, lehnt Collabora mit „No authorized hosts found" ab. OFFICE_ALIASGROUP=http://app:8080 OFFICE_SSL=false OFFICE_SSL_TERMINATION=false # true nur, wenn davor wirklich HTTPS endet