Environment
- Nextcloud Server: 34.0.1.2
- Whiteboard app: 1.5.9
- Whiteboard Collaboration Backend: 1.5.9 (
ghcr.io/nextcloud-releases/whiteboard:stable)
- Deployment:
- Nextcloud running on a dedicated server
- Whiteboard backend running on Docker
- Nginx reverse proxy
- HTTPS enabled
Problem
Whiteboard opens normally, but real-time collaboration does not work.
The browser never establishes a WebSocket connection to the collaboration backend because the backend URL is missing from the generated Content Security Policy.
Browser console shows:
Connecting to 'wss://whiteboard.example.com/socket.io/?EIO=4&transport=websocket'
violates the following Content Security Policy directive:
connect-src
'self'
blob:
...
wss://notification.example.com
The Whiteboard backend is not included in connect-src.
As a result:
- no WebSocket connection is attempted
- no request reaches the Whiteboard backend
- Docker logs remain empty
- collaboration never starts
Backend verification
The backend itself works correctly.
Polling succeeds:
GET /socket.io/?EIO=4&transport=polling
200 OK
0{"sid":"...","upgrades":["websocket"], ...}
WebSocket upgrade also succeeds through Nginx.
JWT configuration is correct.
collabBackendUrl is configured correctly.
Therefore the backend and reverse proxy are functioning correctly.
Investigation
The CSP listener is correctly registered:
$context->registerEventListener(
AddContentSecurityPolicyEvent::class,
AddContentSecurityPolicyListener::class
);
The listener contains the following early return:
if (!$this->isPageLoad() || !$this->isWhiteboardPage()) {
return;
}
Workaround
As a test, I removed the conditional completely in apps/whiteboard/lib/Listener/AddContentSecurityPolicyListener.php file:
public function handle(Event $event): void {
if (!$event instanceof AddContentSecurityPolicyEvent) {
return;
}
$domains = $this->configService->getCollabBackendCspConnectDomains();
$policy = new EmptyContentSecurityPolicy();
foreach ($domains as $domain) {
$policy->addAllowedConnectDomain($domain);
}
$event->addPolicy($policy);
}
Immediately after this modification:
- wss://whiteboard.example.com appeared in the CSP
- the browser connected successfully
- WebSocket connection was established
- collaboration started working normally
No other configuration changes were required.
Suspected cause
One of these conditions appears to incorrectly evaluate to false:
or
preventing the CSP from being added even though the Whiteboard viewer is active.
This may be a regression affecting Nextcloud 34.x, where the current request path or script name no longer matches the assumptions made by the listener.
Expected behavior
Whenever a Whiteboard document is opened and collaboration is required, the Whiteboard collaboration backend should always be added to the generated connect-src CSP so the browser can establish the Socket.IO/WebSocket connection.
Actual behavior
The CSP listener exits early, the collaboration backend is omitted from connect-src, and all WebSocket connections are blocked by the browser before reaching the backend.
Environment
ghcr.io/nextcloud-releases/whiteboard:stable)Problem
Whiteboard opens normally, but real-time collaboration does not work.
The browser never establishes a WebSocket connection to the collaboration backend because the backend URL is missing from the generated Content Security Policy.
Browser console shows:
The Whiteboard backend is not included in connect-src.
As a result:
Backend verification
The backend itself works correctly.
Polling succeeds:
WebSocket upgrade also succeeds through Nginx.
JWT configuration is correct.
collabBackendUrl is configured correctly.
Therefore the backend and reverse proxy are functioning correctly.
Investigation
The CSP listener is correctly registered:
The listener contains the following early return:
Workaround
As a test, I removed the conditional completely in
apps/whiteboard/lib/Listener/AddContentSecurityPolicyListener.phpfile:Immediately after this modification:
No other configuration changes were required.
Suspected cause
One of these conditions appears to incorrectly evaluate to false:
isPageLoad()or
isWhiteboardPage()preventing the CSP from being added even though the Whiteboard viewer is active.
This may be a regression affecting Nextcloud 34.x, where the current request path or script name no longer matches the assumptions made by the listener.
Expected behavior
Whenever a Whiteboard document is opened and collaboration is required, the Whiteboard collaboration backend should always be added to the generated
connect-srcCSP so the browser can establish the Socket.IO/WebSocket connection.Actual behavior
The CSP listener exits early, the collaboration backend is omitted from
connect-src, and all WebSocket connections are blocked by the browser before reaching the backend.