Nextcloud Office - anonymous public shares: editor menu / toolbar broken for guests (built-in CODE & external CODE server)

Summary

When a public link (anonymous) recipient opens an Office document, they can edit the document, but the top menu / file menu is missing or unusable for the guest user (so they can’t use Save/Download/etc). This happens with both:

  • the built-in CODE server (Nextcloud internal)
  • an external Collabora server (office.domain)

So it appears independent of whether CODE or external Collabora is used.

I’ve tried the usual debugging steps (detailed below). Posting this to ask for a focused fix/diagnosis: is this a configuration issue (CSP / WOPI / proxy / headers / guest handling) or a bug in richdocuments / Nextcloud?

There is also an empty bar that seems to have to do with being a guest user at the bottom of the screen.

https://cloud.domain/s/(hash)?dir=/?dir=/&editing=false&openfile=true upon redirect.

The Basics

  • Nextcloud server version: 32.0.5.0
  • Collabora / CODE: Collabora Online Dev Edition 25.04.8.1 (external) and built-in CODE also reproduces the issue.
  • Nextcloud container internal IP: 172.19.0.6
  • Collabora container internal IP: 172.19.0.5
  • Public domains (anonymised): cloud.domain (Nextcloud public URL), office.domain (Collabora public URL)
  • Reverse proxy: nginx 1.28.1 in front of the Docker stack (proxying to Nextcloud container on localhost)
  • PHP version: PHP/8.3.30
  • Operating system and version: Ubuntu 24.04.3 LTS
  • Is this the first time you’ve seen this error? Yes, though I don’t know when it appeared for sure.
  • When did this problem seem to first start? After upgrading to Nextcloud 32.x (exact minor update unclear, but issue did not exist previously)
  • Installation method (e.g., AIO, NCP, Bare Metal/Archive, etc.) Docker Compose based on nextcloud:32.0.5 image **
  • Are you using Cloudflare, mod_security, or similar? No. No CDN, no WAF, no mod_security. Only nginx reverse proxy in front of Docker, but Apache also runs in Docker container.

Summary of the issue you are facing

  • Main File, Home, Insert, Layout, References etc. menu appears only for logged in users - doesn’t show up for anonymous (shared public link) sessions - editing area works and edits are saved.
  • The toolbar/menu below is also sometimes partly hidden.
  • Console shows a TypeError in GuestNamePicker.vue (reading .value of null).
  • Collabora returns 404s for many /browser/<hash>/images/... assets.
  • Nextcloud reports cURL timeouts when calling Collabora /cool/convert-to/png.

Steps to reproduce

  1. Create a public share for a document and enable editing on the share.
  2. Open the public share link in a browser (incognito recommended to avoid cached CSP).
  3. The document loads and is editable, but the top editor menu/file menu is missing or unresponsive for the anonymous user.
  4. Open DevTools → Console & Network to see errors (see logs below).

This reproduces with both:

  • External Collabora at https://office.domain (WOPI external server)
  • Built-in CODE (internal Nextcloud CODE) — same UX bug

Log entries

Nextcloud

"Failed to convert preview: cURL error 28: Operation timed out after 5002 milliseconds ... for https://office.domain/cool/convert-to/png"

Browser console (selected)


TypeError: Cannot read properties of null (reading 'value') at GuestNamePicker.vue:90
Loading failed for script https://office.domain/browser/<hash>/global.js  (blocked or 404)
Content-Security-Policy: blocked a script from office.domain (script-src)
Request for font "Ubuntu Sans" blocked at visibility level 2 (requires 3)

Collabora (selected)

WRN FileServerRequestHandler: File not found: Invalid URI request (hash): [/browser/<hash>/images/dark/lc_settings.svg]
WRN systemplate directory [/opt/cool/systemplate] is read-only
FTL Failed to initialize COOLWSD: File not found: /etc/coolwsd/coolwsd.xml  (when volumes were not mapped / permissions wrong)

Nginx log (selected)


[external client IP] "GET /s/<public-share-id>?dir=/&editing=false&openfile=true HTTP/2.0" 200
[external client IP] "POST /apps/richdocuments/token HTTP/2.0" 200
[external client IP] "POST /browser/<session-id>/cool.html?WOPISrc=https://cloud.domain/index.php/apps/richdocuments/wopi/files/
<file-id> HTTP/2.0" 200
[external client IP] "GET /cool/https://cloud.domain/index.php/apps/richdocuments/wopi/files/
<file-id>/ws HTTP/1.1" 101
[internal container IP] "GET /index.php/apps/richdocuments/wopi/files/<file-id>?access_token=<token> HTTP/1.1" 200 "COOLWSD HTTP Agent"
[internal container IP] "GET /index.php/apps/richdocuments/wopi/settings?type=systemconfig HTTP/1.1" 200 "COOLWSD HTTP Agent"

Configuration

Here’s the config output. Some things are relics of me really trying everything to get it to work, e.g. additional trusted domains. Removed things that are a bit irrelevant.

###nextcloud

{
    "system": {
        "trusted_domains": {
            "0": "localhost",
            "1": "cloud.domain",
            "2": "talk.domain",
            "3": "rec.domain",
            "5": "nc_app",
            "6": "172.19.0.6",
            "7": "172.19.0.5",
            "100": "office.domain"
        },
        "trusted_proxies": "***REMOVED SENSITIVE VALUE***",
(Actually: 'trusted_proxies' => ['172.19.0.0/16','::1','127.0.0.1'],)
        "forwarded_for_headers": [
            "HTTP_X_FORWARDED_FOR"
        ],
        "version": "32.0.5.0",
        "dbtype": "pgsql",
        "dbpersistent": false,
        "installed": true,
        "memcache.local": "\\OC\\Memcache\\APCu",
        "memcache.distributed": "\\OC\\Memcache\\Redis",
        "memcache.locking": "\\OC\\Memcache\\Redis",
        "redis": {
            "host": "***REMOVED SENSITIVE VALUE***",
            "password": "***REMOVED SENSITIVE VALUE***",
            "port": 6379
        },
        "filelocking.enabled": true,
        "apps_paths": [
            {
                "path": "\/var\/www\/html\/apps",
                "url": "\/apps",
                "writable": false
            },
            {
                "path": "\/var\/www\/html\/custom_apps",
                "url": "\/custom_apps",
                "writable": true
            }
        ],
        "overwrite.cli.url": "https:\/\/cloud.domain",
        "overwritehost": "cloud.domain",
        "overwriteprotocol": "https",
        "overwritewebroot": "\/",
        "loglevel": 2,
        "log_type": "file",
        "logfile": "\/var\/www\/html\/data\/nextcloud.log",
        "log_rotate_size": 10485760,
        "enable_previews": true,
        "preview_max_x": 2048,
        "preview_max_y": 2048,
        "preview_max_memory": 2048,
        "check_data_directory_permissions": false,
        "auth.bruteforce.protection.enabled": true,
        "ratelimit.protection.enabled": true,
        "twofactor_enforced": "true",
        "twofactor_enforced_groups": [],
        "twofactor_enforced_excluded_groups": [
            "guest_app",
            "admin"
        ],
        "files_external_allow_create_new_local": true,
        "davstorage.request_timeout": 60,
        "htaccess.RewriteBase": "\/",
        "upgrade.disable-web": true,
        "memories.db.triggers.fcu": true,
        "memories.exiftool": "\/var\/www\/html\/custom_apps\/memories\/bin-ext\/exiftool-amd64-glibc",
        "memories.vod.path": "\/var\/www\/html\/custom_apps\/memories\/bin-ext\/go-vod-amd64",
        "app_install_overwrite": [
            "maps",
            "health"
        ],
        "maintenance": false,
        "config_preset": 1,
    }
}

Richdocuments app

"richdocuments": {
  "public_wopi_url": "https://office.domain",
  "wopi_allowlist": "127.0.0.1,172.19.0.0/16,172.19.0.4,https://cloud.domain",
  "wopi_url": "https://office.domain:443"
}

Nginx

Both cloud.domain and office.domain are served via nginx.

The office.domain vhost proxies /browser/ and /cool/ directly to the CODE container.
Headers are passed through without modification.

I can provide the relevant location /browser/ and location /cool/ blocks if needed.

What I tried

  • Verified richdocuments config (WOPI URLs, allowlist) and guests app is enabled (though that doesn’t seem to be linked).

  • Added internal Docker IPs to Nextcloud trusted_domains / trusted_proxies.

  • Tested with external Collabora (office.domain) and with built-in CODE — same issue.

  • Adjusted nginx CSP to be permissive for office.domain and cloud.domain (to rule out CSP), cleared browser cache, tested in incognito.

  • Confirmed Nextcloud still sends CSP headers; investigated using more_set_headers (nginx-extras) to override, but nginx-extras cannot be installed on this host due to held/broken package dependencies.

  • Confirmed WOPI requests succeed (no 401/403, no “host not authorized” errors), and WebSocket upgrade succeeds (101)

  • Ensured Collabora container had persisted folders mapped (/etc/coolwsd, /var/lib/collabora/data), set ownership to Collabora UID, copied coolwsd.xml into mapped folder.

  • Observed Collabora 404s for /browser/<hash>/images/... and many CSP/script blocks in the browser console.

  • Restarted services/containers multiple times and verified logs.

Open questions / things to confirm

  1. Anonymous public-link users can edit documents, but the editor menu/toolbar is broken (built-in CODE and external Collabora). Console shows GuestNamePicker.vue TypeError and CSP/script 404s.Could this be caused by a change in richdocuments, richdocumentscode, or Nextcloud core? Any known workaround or patch?
  2. CSP & proxy: With nginx as reverse proxy, should CSP be adjusted in nginx or perhaps in Nextcloud/Apache config? Is more_set_headers + nginx-extras required, or can Nextcloud itself emit headers allowing office.domain + blob: + data:? (IF this is part of the problem!)
  3. WOPI host list: What exactly should go in Collabora <wopi> alias_groups and Nextcloud wopi_allowlist for:
    • Public hosts (cloud.domain, office.domain)

    • Docker internal IPs (172.19.0.5 / 172.19.0.6 / 172.19.0.0/16)
      Should both https://cloud.domain and https://cloud.domain:443 be listed?

  4. Is the GuestNamePicker.vue TypeError a known issue with anonymous guests missing a required DOM/JS value?

Thanks in advance for any and all clarity you can provide!

Is that really your full richdocuments config (output of occ config:list richdocuments)
?

Are you being promoted to get a guest name when you visit the public share?

That was the lot unless I truncated it to reduce how much space stuff was taking up, but I don’t think so. And yeah the prompt to enter a Guest name would show up.

TBH, I’ve felt like giving up and switching over to Apache as a reverse proxy for Nextcloud and everything else on the site, so htaccess is better managed. But, alas, I’m having trouble with that now, too. Sigh.

Wait, here’s the lot. I switched back to Nginx. :smiley:

{
“apps”: {
“richdocuments”: {
“installed_version”: “9.0.2”,
“types”: “filesystem,prevent_group_restriction”,
“doc_format”: “”,
“wopi_allowlist”: “127.0.0.1,172.19.0.0/16,172.19.0.4,https://cloud.domain,https://office.domain,http://office.domain,
“wopi_url”: “https://cloud.domain/custom_apps/richdocumentscode/proxy.php?req=”,
“public_wopi_url”: “https://cloud.domain”,
“disable_certificate_verification”: “yes”,
“enabled”: “no”,
“canonical_webroot”: “https://cloud.domain.com/”,
“external_apps”: “collabora:hash,”,
“wopi_callback_url”: “”,
“wopi_timeout”: “30”,
“edit_groups”: “”
}
}
}

That may be in weird, damaged state, though, due to the attempt to switch to apache. :smiley: I

A side note is that I think this all has to do with the reverse proxy situation, and maybe things not being passed properly. I didn’t solve it, though, so can’t say for sure. The nginx server is easier for me on the outside. It just irritated me needing to run nginx and apache, but it’s not so big a deal.

Edit:

No - it seems, the “Whiteboard” app is the problem here. Even though it should be fixed, the “Whiteboard” app still damages public share pages.

So just disable “Whiteboard” - there is no need to apply any custom CSS.

I also reported this on Github since it affects all public shares, not only Nextcloud Office: When Whiteboard is active, public shares don't work any longer ¡ Issue #940 ¡ nextcloud/whiteboard ¡ GitHub

1 Like

@codewordcreative just to be sure, your guests have access to the app right?

I believe it is not about access rights - see my comment about the “Whiteboard” app. It is reproducable - enable “Whiteboard” and then public shares get moved up around 50px because “Whiteboard” adds it’s own HTML/CSS rules to the share view, even if you share an Nextcloud Office document or a folder.

1 Like

I just installed the update of “Whiteboard” to version 1.5.3. This seems to fix the problems with public shares.

1 Like

You’re right! I just updated it and the problem has disappeared! I spent so long trying to fix it, convinced it was my own fault due to all these other less serious errors showing up in the browser…

Whatever, it does work now. Thank you! I’ll also be mindful of that sort of interaction in future. Thanks. How did you discover it, out of interest?

The remaining warnings, if interested:

(index.mjs:51 [WARN] viewer: Some mimes were ignored because they are not enabled in the server previews config Object
log @ index.mjs:51
index.mjs:51 [WARN] viewer: No files provided, skipping update Object
log @ index.mjs:51
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
office.domain/browser/278cb3481b/images/dark/lc_multipageview.svg:1 Failed to load resource: the server responded with a status of 404 ()
global.js:1 Received Host_PostmessageReady.
bundle.js:23277 Blocked autofocusing on a element in a cross-origin subframe.
onAdd @ bundle.js:23277
office.codewordcreative.com/browser/278cb3481b/images/dark/lc_settings.svg:1`` Failed to load resource: the server responded with a status of 404 ()
cool.html?WOPISrc=https%3A%2F%2Fcloud.domain%2Findex.php%2Fapps%2Frichdocuments%2Fwop…:1 The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
cool.html?WOPISrc=https%3A%2F%2Fcloud.domain%2Findex.php%2Fapps%2Frichdocuments%2Fwop…:1 The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
office.domain/browser/278cb3481b/images/dark/lc_overflow-morebutton.svg:1 Failed to load resource: the server responded with a status of 404 ()
cool.html?WOPISrc=https%3A%2F%2Foffice.domain%2Findex.php%2Fapps%2Frichdocuments%2Fwop…:1 The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
cool.html?WOPISrc=https%3A%2F%``2Foffice.codewordcreative.com``%2Findex.php%2Fapps%2Frichdocuments%2Fwop…:1 The Content-Security-Policy directive ‘default-src’ contains the keyword ‘none’ alongside with other source expressions. The keyword ‘none’ must be the only source expression in the directive value, otherwise it is ignored.
TileWorker.js:31 CanvasTileWorker initialised
TileWorker.js:31 CanvasTileWorker initialised
TileWorker.js:31 CanvasTileWorker initialised
TileWorker.js:31 CanvasTileWorker initialised
office.domain/browser/278cb3481b/images/dark/lc_searchdialog.svg:1 Failed to load resource: the server responded with a status of 404 ()
lc_searchdialog.svg:1 Failed to load resource: the server responded with a status of 404 ()

I discovered this by examining the source code of the public share page and because other public shares, like upload folders, also didn’t show in the right way. In the source code I could see some CSS classes indicating that some parts of the “Whiteboard” app seemed to be present as well.

About the remaining warnings: this is all from Collabora itself and I have more or less the same messages here. As long as it works I would just ignore that. However you can report this at Github if you want to: https://github.com/CollaboraOnline/online/issues

1 Like

Nice. I was looking at the code but focusing too much on errors. I did try manually overwriting the CSS but rather foolishly didn’t check to see the actual classes affecting things. Of course, overwrites are also limited in effectiveness with the frames anyway.

Thanks for sharing - I’ll know next time to not so rapidly assume it’s my fault and look closer at the CSS styles, and try it with different plugins enabled or disabled.

Ha, du bist auch in Berlin. Gerade gesehen. Vielen Dank noch mal!