Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collabora unable to open documents, coolwsd can't seem to collabora-te with Apache's proxy #2192

Closed
DigitalLeaves opened this issue May 7, 2022 · 15 comments

Comments

@DigitalLeaves
Copy link

DigitalLeaves commented May 7, 2022

Describe the bug

Hello! I am trying to get Collabora to work on our subdomain (Debian 11). I did a fresh installation (without docker) using the collaboraoffice.com packages here.
I think NextCloud is going to be a game-changer, but I am stuck with this. Can you please help me?

I configured Collabora and it is working and listening on localhost:

localhost:~# netstat -putan | grep LISTEN | grep coolwsd
tcp6       0      0 :::9980                 :::*                    LISTEN      55874/coolwsd       

NextCloud detects Collabora nicely as you can see.

Screenshot 2022-05-07 at 11 31 24

However, when I try to create or open a new document, I had the dreaded white screen of death:

Screenshot 2022-05-07 at 11 32 06

These are the logs from Apache:

==> /var/log/apache2/collabora_error.log <==
[Sat May 07 09:47:56.666693 2022] [proxy_http:error] [pid 55895] (20014)Internal error (specific information not available): [client 94.133.242.174:55346] AH01102: error reading status line from remote server 127.0.0.1:9980
[Sat May 07 09:47:56.666896 2022] [proxy:error] [pid 55895] [client 94.133.242.174:55346] AH00898: Error reading from remote server returned by /cool/https:/cloud.mydomain.com/index.php/apps/richdocuments/wopi/files/672_ocmaqq15fyvi?access_token=hWzvsopvM1WhwyRuVxUPJ2EEqtb1nVSy&access_token_ttl=0&permission=edit/ws

==> /var/log/apache2/other_vhosts_access.log <==
collabora.mydomain.com:443 94.133.242.174 - - [07/May/2022:09:47:56 +0000] "GET /cool/https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi%3Faccess_token%3DhWzvsopvM1WhwyRuVxUPJ2EEqtb1nVSy%26access_token_ttl%3D0%26permission%3Dedit/ws?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&compat=/ws HTTP/1.1" 502 1199 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36"

Which seems to indicate some kind of Proxy error. If I navigate to https:/cloud.mydomain.com/index.php/apps/richdocuments/wopi/files/672_ocmaqq15fyvi?access_token=hWzvsopvM1WhwyRuVxUPJ2EEqtb1nVSy&access_token_ttl=0&permission=edit/ws I see the information perfectly displayed:

{
    "BaseFileName": "New document.docx",
    "Size": 7567,
    "Version": "0",
    "UserId": "ignacio",
    "OwnerId": "ignacio",
    "UserFriendlyName": "ignacio",
    "UserExtraInfo": {
    "avatar": "https://cloud.mydomain.com/index.php/avatar/ignacio/32",
    "is_admin": true
    },
    "UserCanWrite": true,
    "UserCanNotWriteRelative": false,
    "PostMessageOrigin": "https://cloud.mydomain.com/",
    "LastModifiedTime": "2022-05-07T08:44:16.000000Z",
    "SupportsRename": true,
    "UserCanRename": true,
    "EnableInsertRemoteImage": true,
    "EnableShare": true,
    "HideUserList": "",
    "DisablePrint": false,
    "DisableExport": false,
    "DisableCopy": false,
    "HideExportOption": false,
    "HidePrintOption": false,
    "DownloadAsPostMessage": false
}

I also see these from time to time:

[Sat May 07 11:05:45.375905 2022] [core:error] [pid 57958] [remote 127.0.0.1:9980] AH01961:  failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine]
[Sat May 07 11:05:45.375964 2022] [proxy:error] [pid 57958] AH00961: https: failed to enable ssl support for 127.0.0.1:9980 (127.0.0.1)

But SSLProxyEngine is On.

The browser's log may indicate some kind of issue with the Web Socket connection:

Screenshot 2022-05-07 at 11 31 55

However, my Apache configuration follows the official documentation.

<VirtualHost *:443>
  ServerName collabora.mydomain.com:443

  # SSL configuration, you may want to take the easy route instead and use Let's Encrypt!
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/collabora.mydomain.com/cert.pem
  SSLCertificateChainFile /etc/letsencrypt/live/collabora.mydomain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/collabora.mydomain.com/privkey.pem

  SSLProtocol             all -SSLv2 -SSLv3
  # SSLProtocol -all +TLSv1.3 +TLSv1.2
  SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
  SSLHonorCipherOrder     on

  # Encoded slashes need to be allowed
  AllowEncodedSlashes On 
# NoDecode

  # Container uses a unique non-signed certificate
  SSLProxyEngine On
  SSLProxyVerify None
  SSLProxyCheckPeerCN Off
  # SSLProxyCheckPeerName Off

  # keep the host
  ProxyPreserveHost On


  # static html, js, images, etc. served from coolwsd
  # loleaflet/browser is the client part of Collabora Online
  ProxyPass           /browser https://127.0.0.1:9980/browser retry=0
  ProxyPassReverse    /browser https://127.0.0.1:9980/browser

  # WOPI discovery URL
  ProxyPass           /hosting/discovery https://127.0.0.1:9980/hosting/discovery retry=0
  ProxyPassReverse    /hosting/discovery https://127.0.0.1:9980/hosting/discovery

  # Capabilities
  ProxyPass           /hosting/capabilities https://127.0.0.1:9980/hosting/capabilities retry=0
  ProxyPassReverse    /hosting/capabilities https://127.0.0.1:9980/hosting/capabilities

  # Main websocket
  ProxyPassMatch "/cool/(.*)/ws$" ws://127.0.0.1:9980/cool/$1/ws nocanon

  # Admin Console websocket
  ProxyPass   /cool/adminws ws://127.0.0.1:9980/cool/adminws

  # Download as, Fullscreen presentation and Image upload operations
  ProxyPass           /cool https://127.0.0.1:9980/cool
  ProxyPassReverse    /cool https://127.0.0.1:9980/cool
  ProxyPass           /lool https://127.0.0.1:9980/cool
  ProxyPassReverse    /lool https://127.0.0.1:9980/cool

  ErrorLog /var/log/apache2/collabora_error.log
</VirtualHost>

If I go to https://collabora.mydomain.com/cool, I get a "This page is not working" 400 error.
Curl (see log in details below) does not show any particular error, just closes the connection with a 400.

I have tried the solutions shown here, including:

  • changing the hexify variable on coolwsd.xml (true and false):
    <hexify_embedded_urls desc="Enable to protect encoded URLs from getting decoded by intermediate hops. Particularly useful on Azure deployments" type="bool" default="false"></hexify_embedded_urls>

  • changing the SSLProtocol variables of Apache:
SSLProtocol             all -SSLv2 -SSLv3
# SSLProtocol -all +TLSv1.3 +TLSv1.2

Without success.

To Reproduce
Steps to reproduce the behavior:

  1. Well, install Nextcloud on a VPS using the Debian official packages from collaboraoffice.com
  2. Set up reverse proxy
  3. Connect Collabora to NextCloud on Admin settings
  4. Try to create or open a document

Expected behavior
I should be able to open and edit the document.

Screenshots

See above.

Client details:

  • OS: [e.g. iOS]" Server: MacOS Monterey 12.2.1 (21D62)
  • Browser [e.g. chrome, safari] Chrome Version 101.0.4951.54 (Official Build) (x86_64) on a
  • Version [e.g. 22] 24.0.0
  • Device: [e.g. iPhone6, desktop] Desktop

Server details

Operating system: Debian Linux 11

Web server: Apache 2.4.53

Database: MariaDB 1:10.5.15-0+deb11u1

PHP version: PHP 7.4.28 (cli) (built: Feb 17 2022 16:17:19) ( NTS )

Nextcloud version: 24.0.0

Version of the richdocuments app Didn't find this, if this is "Text", it is 3.5.1.

Version of Collabora Online NextCloud Office 6.0.0

Logs

See above

Nextcloud log (data/nextcloud.log)

(nothing relevant here)

Browser log

cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264 WebSocket connection to 'wss://collabora.mydomain.com/cool/https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi%3Faccess_token%3DNil4BIb7RcGd7g6slHl0uDaASL9uNfUc%26access_token_ttl%3D0/ws?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&compat=/ws' failed: 
global.createWebSocket @ cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264
(anonymous) @ cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264
(anonymous) @ cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264
bundle.js:1 Blocked autofocusing on a <textarea> element in a cross-origin subframe.
onAdd @ bundle.js:1
_layerAdd @ bundle.js:1
whenReady @ bundle.js:1
addLayer @ bundle.js:1
initialize @ bundle.js:1
NewClass @ bundle.js:1
L.map @ bundle.js:1
(anonymous) @ bundle.js:1
(anonymous) @ bundle.js:1
(anonymous) @ bundle.js:1
cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264 WebSocket connection to 'wss://collabora.mydomain.com/cool/https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi%3Faccess_token%3DNil4BIb7RcGd7g6slHl0uDaASL9uNfUc%26access_token_ttl%3D0%26permission%3Dedit/ws?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&compat=/ws' failed: 
global.createWebSocket @ cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264
connect @ bundle.js:1
loadDocument @ bundle.js:1
(anonymous) @ bundle.js:1
(anonymous) @ bundle.js:1
(anonymous) @ bundle.js:1
cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264 WebSocket connection to 'wss://collabora.mydomain.com/cool/https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi%3Faccess_token%3DNil4BIb7RcGd7g6slHl0uDaASL9uNfUc%26access_token_ttl%3D0%26permission%3Dedit/ws?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&compat=/ws' failed: 
global.createWebSocket @ cool.html?WOPISrc=https%3A%2F%2Fcloud.mydomain.com%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F672_ocmaqq15fyvi&title=New%20document.docx&lang=en&closebutton=1&revisionhistory=1:264
connect @ bundle.js:1
loadDocument @ bundle.js:1
_activate @ bundle.js:1
(anonymous) @ bundle.js:1
Office.vue:198 FAILED
(anonymous) @ Office.vue:198
setTimeout (async)
(anonymous) @ Office.vue:197
u @ runtime.js:63
(anonymous) @ runtime.js:294
(anonymous) @ runtime.js:119
ae @ collabora.js:48
i @ collabora.js:48
(anonymous) @ collabora.js:48
(anonymous) @ collabora.js:48
load @ Office.vue:190
(anonymous) @ Office.vue:184
u @ runtime.js:63
(anonymous) @ runtime.js:294
(anonymous) @ runtime.js:119
ae @ collabora.js:48
i @ collabora.js:48
Promise.then (async)
ae @ collabora.js:48
i @ collabora.js:48
Promise.then (async)
ae @ collabora.js:48
i @ collabora.js:48
(anonymous) @ collabora.js:48
(anonymous) @ collabora.js:48
mounted @ Office.vue:162
We @ vue.runtime.esm.js:1863
un @ vue.runtime.esm.js:4235
insert @ vue.runtime.esm.js:3158
_ @ vue.runtime.esm.js:6390
bo.nodeOps @ vue.runtime.esm.js:6609
e._update @ vue.runtime.esm.js:3963
r @ vue.runtime.esm.js:4081
bn.get @ vue.runtime.esm.js:4495
bn.run @ vue.runtime.esm.js:4570
An @ vue.runtime.esm.js:4326
(anonymous) @ vue.runtime.esm.js:1989
et @ vue.runtime.esm.js:1915
Promise.then (async)
Ke @ vue.runtime.esm.js:1942
it @ vue.runtime.esm.js:1999
(anonymous) @ vue.runtime.esm.js:4418
bn.update @ vue.runtime.esm.js:4560
de.notify @ vue.runtime.esm.js:730
set @ vue.runtime.esm.js:1055
Cn.set @ vue.runtime.esm.js:4644
(anonymous) @ Viewer.vue:386
u @ runtime.js:63
(anonymous) @ runtime.js:294
(anonymous) @ runtime.js:119
Wa @ Download.vue?b226:19
a @ Download.vue?b226:19
Promise.then (async)
Wa @ Download.vue?b226:19
a @ Download.vue?b226:19
(anonymous) @ Download.vue?b226:19
(anonymous) @ Download.vue?b226:19
openFile @ Viewer.vue:344
file @ Viewer.vue:256
We @ vue.runtime.esm.js:1863
bn.run @ vue.runtime.esm.js:4584
An @ vue.runtime.esm.js:4326
(anonymous) @ vue.runtime.esm.js:1989
et @ vue.runtime.esm.js:1915
Promise.then (async)
Ke @ vue.runtime.esm.js:1942
it @ vue.runtime.esm.js:1999
(anonymous) @ vue.runtime.esm.js:4418
bn.update @ vue.runtime.esm.js:4560
de.notify @ vue.runtime.esm.js:730
set @ vue.runtime.esm.js:1055
value @ Viewer.js:183
navigate @ RecommendedFile.vue:142
click @ RecommendedFile.vue?879d:21
Vt @ vue.runtime.esm.js:1863
n @ vue.runtime.esm.js:2188
i._wrapper @ vue.runtime.esm.js:6961
bundle.js:1 missing popover data
closePopover @ bundle.js:1
(anonymous) @ bundle.js:1
setTimeout (async)
onJSDialog @ bundle.js:1
fire @ bundle.js:1
_onJSDialog @ bundle.js:1
_onMessage @ bundle.js:1
showSnackbar @ bundle.js:1
_onSocketClose @ bundle.js:1
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1837755)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1841272)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 missing popover data
closePopover @ bundle.js:1
(anonymous) @ bundle.js:1
setTimeout (async)
onJSDialog @ bundle.js:1
fire @ bundle.js:1
_onJSDialog @ bundle.js:1
_onMessage @ bundle.js:1
showSnackbar @ bundle.js:1
_onSocketClose @ bundle.js:1
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1837755)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1841272)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1837755)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1841272)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1837755)
    at handler (bundle.js:1:1787353)
onMessage @ bundle.js:1
handler @ bundle.js:1
postMessage (async)
sendLocation @ gps.js:167
(anonymous) @ gps.js:183
bundle.js:1 Uncaught TypeError: e.data.startsWith is not a function
    at NewClass.onMessage (bundle.js:1:1841272)
    at handler (bundle.js:1:1787353)

Curl to /cool locally log:


localhost:~# curl -k -vv https://127.0.0.1:9980/cool
*   Trying 127.0.0.1:9980...
* Connected to 127.0.0.1 (127.0.0.1) port 9980 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*  CAfile: /etc/ssl/certs/ca-certificates.crt
*  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
*  subject: CN=cloud.mydomain.com
*  start date: May  6 15:05:39 2022 GMT
*  expire date: Aug  4 15:05:38 2022 GMT
*  issuer: C=US; O=Let's Encrypt; CN=R3
*  SSL certificate verify ok.
> GET /cool HTTP/1.1
> Host: 127.0.0.1:9980
> User-Agent: curl/7.74.0
> Accept: */*
> 
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Mark bundle as not supporting multiuse
< HTTP/1.1 400 Bad Request
< Date: Sat, 07 May 2022 11:19:13
< Server: COOLWSD HTTP Server 21.11.4.2
< Content-Length: 0
< Connection: close
< 
* Closing connection 0
* TLSv1.3 (OUT), TLS alert, close notify (256):
@DigitalLeaves
Copy link
Author

DigitalLeaves commented May 16, 2022

I finally was able to find the answer and make it work! For others in the same situation, in my case, it was due to the fact that I was not using the Secure Web Socket protocol (wss) even though I was using HTTPS.

So I just had to replace this:

ProxyPassMatch "/cool/(.*)/ws$" ws://127.0.0.1:9980/cool/$1/ws nocanon

With this:

ProxyPassMatch "/cool/(.*)/ws$" wss://127.0.0.1:9980/cool/$1/ws nocanon

@ambarusa
Copy link

ambarusa commented Jun 3, 2022

wss:// is already used in the official reverse proxy configuration. I have the same WebSocket errors still :(

@waclaw66
Copy link

waclaw66 commented Dec 8, 2022

I have the same problem but with Nginx reverse proxy, I think the official configuration
https://sdk.collaboraonline.com/docs/installation/Proxy_settings.html#reverse-proxy-settings-in-nginx-config-ssl-termination
is wrong.
Has someone make it work with Nginx?

@waclaw66
Copy link

waclaw66 commented Dec 8, 2022

I've made it work, the problem wasn't in Nginx reverse proxy configuration, but automatically included .php files processing.
There is index.php in the socket url that was processed by php instead of that ^/cool/(.*)/ws$ rule.

@losavard
Copy link

@waclaw66 what did you end up doing to bypass the .php processing?

I'm facing the same issue and fell on this...which gives me hope!

Looking forward to hear back!

@waclaw66
Copy link

@waclaw66 what did you end up doing to bypass the .php processing?

I've used php settings from recommended configuration instead of default php configuration from nginx (/etc/nginx/default.d/php.conf).

@losavard
Copy link

Thanks @waclaw66....guess that wasn't my issue...totally. I think I have a combination of issues here....same wss: error after using the recommended configs as suggested.

From an infrastructure side, my setup is as follows:

INTERNET -> Nginx Reverse-Proxy (secured with Let's encrypt) -> internal processes (collabora and nextcloud on independant VMs using Nginx web server (no proxying, no ssl for the internal servers)).

Everything seems to work with NextCloud and the connection to Collabora is confirmed...only when I try to create or open documents does it fail:

WebSocket connection to 'wss://COLLABDOMAIN/cool/https%3A%2F%2FNEXTCLOUDDOMAIN%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F166_ocg49un0fzeh%3Faccess_token%3DkHyMlMSrxwLGqgUZ7ez6eZIAE53xk5SZ%26access_token_ttl%3D1673592859000%26permission%3Dedit/ws?WOPISrc=https%3A%2F%2FNEXTCLOUDDOMAIN%2Findex.php%2Fapps%2Frichdocuments%2Fwopi%2Ffiles%2F166_ocg49un0fzeh&compat=/ws' failed:

It's clearly failing to create the websocket while looking for wss:// where it doesn't show anywhere in my reverse proxy...a bit lost here...I'm sure it's something simple that I'm overlooking.

This is my current websocket clip from the reverse proxy (Nginx):
# main websocket
location ~ ^/cool/(.*)/ws$ {
proxy_pass http://192.168.x.x:9980;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $http_host;
proxy_read_timeout 36000s;
}

When I change my proxy_pass directive to use ws: (which is what I want) or wss:, nginx -t errors out...and nginx fails to start.

I've turned off everything I can think of in terms of SSL Nextcloud server side to force ws:// instead of wss:// as that's handled by the reverse-proxy (secured)...no matter what, it's still trying to open up a secure socket....which if I was a betting man this is probably the issue (paired with no wss:// in the reverse proxy) seeing as both the collabora and nextcloud server don't use ssl internally....I'm just out of ideas where to look.

I don't want to hijack anything and I'll start a new thread if needed but I figured given the .php angle that had me hopeful, this might be the best place to carry-on.

Appreciate any insight.

Cheers!

@tonytonyistony
Copy link

Im having the same issues. And they came on suddenly and without warning. Everything was working, and now it isnt and Im getting permission errors.

@dolohow
Copy link

dolohow commented Feb 13, 2023

@waclaw66 what did you end up doing to bypass the .php processing?

I've used php settings from recommended configuration instead of default php configuration from nginx (/etc/nginx/default.d/php.conf).

I spent so much time on this, I knew that when I connect to web socket the location block is not fired up. But I didn't notice there is a index.php inside URL. So I changed the order of location blocks, and now it's working.

@ftoledo
Copy link

ftoledo commented Feb 15, 2023

can you share your nginx config settings?

@AllenRoux
Copy link

@waclaw66 what did you end up doing to bypass the .php processing?

I've used php settings from recommended configuration instead of default php configuration from nginx (/etc/nginx/default.d/php.conf).

I spent so much time on this, I knew that when I connect to web socket the location block is not fired up. But I didn't notice there is a index.php inside URL. So I changed the order of location blocks, and now it's working.

Please share the nginx config file

@dolohow
Copy link

dolohow commented Feb 17, 2023

upstream php-handler {
  server 127.0.0.1:9001;
}

# Set the `immutable` cache control options only for assets with a cache busting `v` argument
map $arg_v $asset_immutable {
  "" "";
  default "immutable";
}

server {
  listen 443 ssl http2;
  server_name removed;

  # Path to the root of your installation
  root /home/nextcloud/nextcloud;

  ssl_certificate /etc/letsencrypt/live/removed/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/removed/privkey.pem;
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
  include /etc/letsencrypt/options-ssl-nginx.conf;

  access_log /var/log/nginx/nextcloud.access.log;
  error_log /var/log/nginx/nextcloud.error.log;

  # Prevent nginx HTTP Server Detection
  server_tokens off;

  # HSTS settings
  # WARNING: Only add the preload option once you read about
  # the consequences in https://hstspreload.org/. This option
  # will add the domain to a hardcoded list that is shipped
  # in all major browsers and getting removed from this list
  # could take several months.
  add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;

  # set max upload size and increase upload timeout
  client_max_body_size 512M;
  client_body_timeout 300s;
  fastcgi_buffers 64 4K;

  # Enable gzip but do not remove ETag headers
  gzip on;
  gzip_vary on;
  gzip_comp_level 4;
  gzip_min_length 256;
  gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
  gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;


  # Pagespeed is not supported by Nextcloud, so if your server is built
  # with the `ngx_pagespeed` module, uncomment this line to disable it.
  #pagespeed off;

  # The settings allows you to optimize the HTTP2 bandwitdth.
  # See https://blog.cloudflare.com/delivering-http-2-upload-speed-improvements/
  # for tunning hints
  client_body_buffer_size 512k;

  # HTTP response headers borrowed from Nextcloud `.htaccess`
  add_header Referrer-Policy                      "no-referrer"   always;
  add_header X-Content-Type-Options               "nosniff"       always;
  add_header X-Download-Options                   "noopen"        always;
  add_header X-Frame-Options                      "SAMEORIGIN"    always;
  add_header X-Permitted-Cross-Domain-Policies    "none"          always;
  add_header X-Robots-Tag                         "none"          always;
  add_header X-XSS-Protection                     "1; mode=block" always;

  # Remove X-Powered-By, which is an information leak
  fastcgi_hide_header X-Powered-By;

  # Specify how to handle directories -- specifying `/index.php$request_uri`
  # here as the fallback means that Nginx always exhibits the desired behaviour
  # when a client requests a path that corresponds to a directory that exists
  # on the server. In particular, if that directory contains an index.php file,
  # that file is correctly served; if it doesn't, then the request is passed to
  # the front-end controller. This consistent behaviour means that we don't need
  # to specify custom rules for certain paths (e.g. images and other assets,
  # `/updater`, `/ocm-provider`, `/ocs-provider`), and thus
  # `try_files $uri $uri/ /index.php$request_uri`
  # always provides the desired behaviour.
  index index.php index.html /index.php$request_uri;


  # Rule borrowed from `.htaccess` to handle Microsoft DAV clients
  location = / {
    if ( $http_user_agent ~ ^DavClnt ) {
      return 302 /remote.php/webdav/$is_args$args;
    }
  }

  location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
  }

  # Make a regex exception for `/.well-known` so that clients can still
  # access it despite the existence of the regex rule
  # `location ~ /(\.|autotest|...)` which would otherwise handle requests
  # for `/.well-known`.
  location ^~ /.well-known {
    # The rules in this block are an adaptation of the rules
    # in `.htaccess` that concern `/.well-known`.
    location = /.well-known/carddav { return 301 /remote.php/dav/; }
    location = /.well-known/caldav  { return 301 /remote.php/dav/; }

    location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
    location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

    # Let Nextcloud's API for `/.well-known` URIs handle all other
    # requests by passing them to the front-end controller.
    return 301 /index.php$request_uri;
  }


  # Rules borrowed from `.htaccess` to hide certain paths from clients
  location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
  location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

  # main websocket
  location ~ ^/cool/(.*)/ws$ {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $http_host;
    proxy_read_timeout 36000s;
  }

  # Ensure this block, which passes PHP files to the PHP process, is above the blocks
  # which handle static assets (as seen below). If this block is not declared first,
  # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
  # to the URI, resulting in a HTTP 500 error response.
  location ~ \.php(?:$|/) {
    # Required for legacy support
    rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;

    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    set $path_info $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
    fastcgi_param PATH_INFO $path_info;

    fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
    fastcgi_param front_controller_active true;     # Enable pretty urls
    fastcgi_pass php-handler;

    fastcgi_intercept_errors on;
    fastcgi_request_buffering off;

    fastcgi_max_temp_file_size 0;
  }

  location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
    try_files $uri /index.php$request_uri;
    add_header Cache-Control "public, max-age=15778463, $asset_immutable";
    access_log off;     # Optional: Don't log access to assets

    location ~ \.wasm$ {
      default_type application/wasm;
    }
  }

  location ~ \.woff2?$ {
    try_files $uri /index.php$request_uri;
    expires 7d;         # Cache-Control policy borrowed from `.htaccess`
    access_log off;     # Optional: Don't log access to assets
  }

  # Rule borrowed from `.htaccess`
  location /remote {
    return 301 /remote.php$request_uri;
  }

  # static files
  location ^~ /browser {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # WOPI discovery URL
  location ^~ /hosting/discovery {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # Capabilities
  location ^~ /hosting/capabilities {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # download, presentation and image upload
  location ~ ^/(c|l)ool {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # Admin Console websocket
  location ^~ /cool/adminws {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $http_host;
    proxy_read_timeout 36000s;
  }

  location ^~ /push/ {
    proxy_pass http://127.0.0.1:7867/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    try_files $uri $uri/ /index.php$request_uri;
  }
}


server {
  listen 80;
  server_name removed;

# Prvent nginx HTTP Server Detection
  server_tokens off;

# Enforce HTTPS
  return 301 https://$server_name$request_uri;
}

@AllenRoux
Copy link

  location ^~ /.well-known {
    # The rules in this block are an adaptation of the rules
    # in `.htaccess` that concern `/.well-known`.
    location = /.well-known/carddav { return 301 /remote.php/dav/; }
    location = /.well-known/caldav  { return 301 /remote.php/dav/; }

    location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
    location /.well-known/pki-validation    { try_files $uri $uri/ =404; }

    # Let Nextcloud's API for `/.well-known` URIs handle all other
    # requests by passing them to the front-end controller.
    return 301 /index.php$request_uri;
  }


  # Rules borrowed from `.htaccess` to hide certain paths from clients
  location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)  { return 404; }
  location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console)                { return 404; }

  # main websocket
  location ~ ^/cool/(.*)/ws$ {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $http_host;
    proxy_read_timeout 36000s;
  }

  # Ensure this block, which passes PHP files to the PHP process, is above the blocks
  # which handle static assets (as seen below). If this block is not declared first,
  # then Nginx will encounter an infinite rewriting loop when it prepends `/index.php`
  # to the URI, resulting in a HTTP 500 error response.
  location ~ \.php(?:$|/) {
    # Required for legacy support
    rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;

    fastcgi_split_path_info ^(.+?\.php)(/.*)$;
    set $path_info $fastcgi_path_info;

    try_files $fastcgi_script_name =404;

    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
    fastcgi_param PATH_INFO $path_info;

    fastcgi_param modHeadersAvailable true;         # Avoid sending the security headers twice
    fastcgi_param front_controller_active true;     # Enable pretty urls
    fastcgi_pass php-handler;

    fastcgi_intercept_errors on;
    fastcgi_request_buffering off;

    fastcgi_max_temp_file_size 0;
  }

  location ~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite|map)$ {
    try_files $uri /index.php$request_uri;
    add_header Cache-Control "public, max-age=15778463, $asset_immutable";
    access_log off;     # Optional: Don't log access to assets

    location ~ \.wasm$ {
      default_type application/wasm;
    }
  }

  location ~ \.woff2?$ {
    try_files $uri /index.php$request_uri;
    expires 7d;         # Cache-Control policy borrowed from `.htaccess`
    access_log off;     # Optional: Don't log access to assets
  }

  # Rule borrowed from `.htaccess`
  location /remote {
    return 301 /remote.php$request_uri;
  }

  # static files
  location ^~ /browser {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # WOPI discovery URL
  location ^~ /hosting/discovery {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # Capabilities
  location ^~ /hosting/capabilities {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # download, presentation and image upload
  location ~ ^/(c|l)ool {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Host $http_host;
  }

  # Admin Console websocket
  location ^~ /cool/adminws {
    proxy_pass http://127.0.0.1:9980;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $http_host;
    proxy_read_timeout 36000s;
  }

  location ^~ /push/ {
    proxy_pass http://127.0.0.1:7867/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }

  location / {
    try_files $uri $uri/ /index.php$request_uri;
  }
}

What manual did you use to deploy?

@dolohow
Copy link

dolohow commented Feb 17, 2023

A few I guess, official one plus I combined it with what is written on collabora website, plus something more I guess…

@ftoledo
Copy link

ftoledo commented Feb 17, 2023

I can confirm that put websocket stanza on top of php settings solved the issue!
i cannot believe! =) thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants