Upgraded to 27 from 23 and Web Interface No Longer Works

Yesterday I upgraded to 27 from 23, going one version at a time (i.e. 23->24, 24->25, 25->26, 26->27). I am running the stable-fpm version via Docker. To date, I have never had any issues but now, when I try to use the web interface, nothing works.

First, I couldn’t even see the login form. Then I changed the ContentSecurityPolicy.php file to include nextclound.mydomain.com in all the “allow” stanzas.

Now I can see the login form but it shows the {Product_name} placeholder instead of showing Nextcloud.

I cannot use the web interface to check the security settings (it just spins).
The weather won’t load (it just spins)
The Calendar won’t load (it just spins)

Changing anything in the admin console says error when I try to save.
Clicking on Apps just shows an empty page

Every page in the web interface shows
Content-Security-Policy: The page’s settings blocked the loading of a resource at inline (“script-src”).
in console, and pages beyond login shows a bunch more errors

The strange thing is that because I use the iOS Calendar and Contacts apps (as well as the macOS Calendar and Address Book), all my data is sync’ing just fine, but I need to be able to use the web interface like I used to.

Looking at the nextcloud.log file I see this message over and over again:

{"reqId":"ZT4gHaXQpbRDxzNFHVIDIVHEI","level":0,"time":"2023-10-29T09:04:29+00:00","remoteAddr":"x.x.x.x","user":"--","app":"webdav","method":"PROPFIND","url":"/remote.php/dav/calendars/myusername/","message":"No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured","userAgent":"macOS/12.5.1 (21G83) CalendarAgent/961.4.2","version":"27.1.3.2","exception":{"Exception":"Sabre\\DAV\\Exception\\NotAuthenticated","Message":"No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured","Code":0,"Trace":[{"file":"/var/www/html/3rdparty/sabre/event/lib/WildcardEmitterTrait.php","line":89,"function":"beforeMethod","class":"Sabre\\DAV\\Auth\\Plugin","type":"->","args":[["Sabre\\HTTP\\Request"],["Sabre\\HTTP\\Response"]]},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":456,"function":"emit","class":"Sabre\\DAV\\Server","type":"->","args":["beforeMethod:PROPFIND",[["Sabre\\HTTP\\Request"],["Sabre\\HTTP\\Response"]]]},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":253,"function":"invokeMethod","class":"Sabre\\DAV\\Server","type":"->","args":[["Sabre\\HTTP\\Request"],["Sabre\\HTTP\\Response"]]},{"file":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Server.php","line":321,"function":"start","class":"Sabre\\DAV\\Server","type":"->","args":[]},{"file":"/var/www/html/apps/dav/lib/Server.php","line":365,"function":"exec","class":"Sabre\\DAV\\Server","type":"->","args":[]},{"file":"/var/www/html/apps/dav/appinfo/v2/remote.php","line":35,"function":"exec","class":"OCA\\DAV\\Server","type":"->","args":[]},{"file":"/var/www/html/remote.php","line":172,"args":["/var/www/html/apps/dav/appinfo/v2/remote.php"],"function":"require_once"}],"File":"/var/www/html/3rdparty/sabre/dav/lib/DAV/Auth/Plugin.php","Line":152,"message":"No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured","exception":{},"CustomMessage":"No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured"}}

I am running Apache and this is my vhost config:

<VirtualHost *:443>
        DocumentRoot /var/www/html

        ServerAdmin webmaster@mydomain.com    
        ServerName nextcloud.mydomain.com

        Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload"

        SSLProxyEngine on
        ProxyVia on
        ProxyAddHeaders on
        ProxyPreserveHost on

        ErrorLog "/logs/nextcloud.mydomain.com-error_log"     
        CustomLog "/logs/nextcloud.mydomain.com-access_log" common       

        RewriteEngine On

        RewriteRule ^/.well-known/host-meta /public.php?service=host-meta [QSA,L]
        RewriteRule ^/.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
        RewriteRule ^/\.well-known/carddav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
        RewriteRule ^/\.well-known/caldav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
        RewriteRule ^/.well-known/webfinger /index.php/.well-known/webfinger [R=301,L]
        RewriteRule ^/.well-known/nodeinfo /index.php/.well-known/nodeinfo [R=301,L]

        <Directory /web/letsencrypt>
                AllowOverride All
                Require all granted
                Options FollowSymLinks MultiViews

                <IfModule mod_dav.c>
                        Dav off
                </IfModule>
        </Directory>

        <Directory /var/www/html>
                AllowOverride All
                Require all granted
        </Directory>

        SSLEngine on
        SSLProtocol TLSv1.2
        SSLHonorCipherOrder on
        SSLCipherSuite ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256

        RewriteRule /.well-known/acme-challenge/ - [R,L]
        Alias /.well-known/acme-challenge /letsencrypt/.well-known/acme-challenge

        <Directory /letsencrypt>
        Require all granted
        </Directory>

        SSLCertificateFile "/etc/letsencrypt/live/nextcloud.mydomain.com/fullchain.pem"
        SSLCertificateKeyFile "/etc/letsencrypt/live/nextcloud.mydomain.com/privkey.pem"

        <FilesMatch "\.(php|phar)$">
                SetHandler "proxy:fcgi://nextcloud:9000"
        </FilesMatch>

        DirectoryIndex /index.php index.php

        BrowserMatch ".*MSIE.*" \
        nokeepalive ssl-unclean-shutdown \
        downgrade-1.0 force-response-1.0

        CustomLog "/logs/ssl_request_log" \
        "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

This is my config.php file

<?php
$CONFIG = array (
  'debug' => false,
  'htaccess.RewriteBase' => '/',
  'instanceid' => 'xxxxx',
  'passwordsalt' => 'xxxxx',
  'secret' => 'xxxxx',
  'trusted_domains' => 
  array (
    0 => 'localhost',
    1 => 'nextcloud.mydomain.com',
  ),
  'datadirectory' => '/var/www/html/data',
  'dbtype' => 'pgsql',
  'version' => '27.1.3.2',
  'overwrite.cli.url' => 'https://nextcloud.mydomain.com',
  'overwriteprotocol' => 'https',
  'dbname' => 'mynextcloud',
  'dbhost' => 'postgres:1234',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'dbuser' => 'nextcloud',
  'dbpassword' => 'xxxxx',
  'installed' => true,
  'default_language' => 'en',
  'default_locale' => 'en_US',
  'default_phone_region' => 'US',
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'memcache.distributed' => '\\OC\\Memcache\\Memcached',
  'memcached_servers' => 
  array (
    0 => 
    array (
      0 => 'nextcloud_memcached',
      1 => 11211,
    ),
  ),
  'apps_paths' => 
  array (
    0 => 
    array (
      'path' => '/var/www/html/apps',
      'url' => '/apps',
      'writable' => false,
    ),
    1 => 
    array (
      'path' => '/var/www/html/custom_apps',
      'url' => '/custom_apps',
      'writable' => true,
    ),
  ),
  'maintenance' => false,
  'theme' => '',
  'logfile' => '/var/www/html/data/nextcloud.log',
  'loglevel' => 0,
  'log_rotate_size' => 104857600,
  'data-fingerprint' => 'xxxxx',
  'mail_from_address' => 'webmaster',
  'mail_smtpmode' => 'smtp',
  'mail_sendmailmode' => 'smtp',
  'mail_domain' => 'mydomain.com',
'mail_smtphost' => 'mail.mydomain.com',
  'mail_smtpport' => '587',     
  'mail_smtpauthtype' => 'PLAIN',
  'mail_smtpauth' => 1,
  'mail_smtpname' => 'user@mydomain.com',
  'mail_smtppassword' => 'xxxxx',
  'mail_smtpsecure' => 'tls',
);

Note: I have redacted all sensitive information from this post.

Would love to get this back and working and could really use some guidance. Thanks!

I’m not familiar with docker/fpm variant… but I’m curious about CSP policy. At least docker/Apache doesn’t ship a CSP policy. Did you add CSP yourself?

I’m under impression your config.php is missing overwritehost setting which should be there for correct reverseproxy setup: reverse rpoxy.

The log line you provided has nothing to do with WebUI in my eyes, please provide more logs from reverseproxy, container and browser (F12)

For anyone else having these issues, here’s how I solved it.

Apparently Firefox (and I tested with Safari) both had major bugs due to the new CSP from Nextcloud. Personally, I think it’s a terrible solution when the only thing that works is to disable web security settings, but there was nothing else I could think of after spending so many hours troubleshooting.

Edit the EmptyContentSecurityPolicy.php and look for what I’ve noted:

/* YOU MUST COMMENT OUT THE FOLLOWING STANZA */
/*                      if (is_string($this->useJsNonce)) {
                                if ($this->strictDynamicAllowed) {
                                        $policy .= '\'strict-dynamic\' ';
                                }
                                $policy .= '\'nonce-'.base64_encode($this->useJsNonce).'\'';
                                $allowedScriptDomains = array_flip($this->allowedScriptDomains);
                                unset($allowedScriptDomains['\'self\'']);
                                $this->allowedScriptDomains = array_flip($allowedScriptDomains);
                                if (count($allowedScriptDomains) !== 0) {
                                        $policy .= ' ';
                                }
                        }
*/

/* YOU MUST COMMENT OUT THE FOLLOWING LINES */
//                      if ($this->inlineScriptAllowed) {
                                $policy .= ' \'unsafe-inline\'';
//                      }

and in the ContentSecurityPolicy.php you have to update it like this:

class ContentSecurityPolicy extends EmptyContentSecurityPolicy {
        /** @var bool Whether inline JS snippets are allowed */
        protected $inlineScriptAllowed = false;
        /** @var bool Whether eval in JS scripts is allowed */
        protected $evalScriptAllowed = false;
        /** @var bool Whether strict-dynamic should be set */
        protected $strictDynamicAllowed = false;
        /** @var array Domains from which scripts can get loaded */
        protected $allowedScriptDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];
        /**
         * @var bool Whether inline CSS is allowed
         * TODO: Disallow per default
         * @link https://github.com/owncloud/core/issues/13458
         */
        protected $inlineStyleAllowed = true;
        /** @var array Domains from which CSS can get loaded */
        protected $allowedStyleDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];
        /** @var array Domains from which images can get loaded */
        protected $allowedImageDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
                'data:',
                'blob:',
        ];
        /** @var array Domains to which connections can be done */
        protected $allowedConnectDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
 	    ];
        /** @var array Domains from which media elements can be loaded */
        protected $allowedMediaDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];
        /** @var array Domains from which object elements can be loaded */
        protected $allowedObjectDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];
        /** @var array Domains from which iframes can be loaded */
        protected $allowedFrameDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];
        /** @var array Domains from which fonts can be loaded */
        protected $allowedFontDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
                'data:',
        ];
        /** @var array Domains from which web-workers and nested browsing content can load elements */
        protected $allowedChildSrcDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];

        /** @var array Domains which can embed this Nextcloud instance */
        protected $allowedFrameAncestors = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];

        /** @var array Domains from which web-workers can be loaded */
        protected $allowedWorkerSrcDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];

        /** @var array Domains which can be used as target for forms */
        protected $allowedFormActionDomains = [
                '\'self\'',
                'nextcloud.mydomain.com',
        ];

        /** @var array Locations to report violations to */
        protected $reportTo = [];
}

I also had to upgrade from using memcached to redis (so much fun!):

This is the new portion of my docker-compose file:

nextcloud_redis:
    restart: unless-stopped
    image: redis:alpine
    container_name: nextcloud_redis
    command: redis-server --requirepass ${REDIS_HOST_PASSWORD} --maxmemory-policy volatile-ttl --maxmemory 256mb
    logging:
      driver: "json-file"
      options:
        max-size: 10m
        max-file: "5"
    volumes:
      - /server/data/nextcloud/redis:/data
      - /etc/localtime:/etc/localtime:ro
      - /etc/timezone:/etc/timezone:ro
    environment:
      - REDIS_REPLICATION_MODE=master
    networks:
      nextcloud: {}

and these are the new lines in the config.php

'memcache.local' => '\\OC\\Memcache\\APCu',
  'memcache.locking' => '\\OC\\Memcache\\Redis',
  'filelocking.enabled' => 'true',
  'redis' => 
  array (
    'host' => 'nextcloud_redis',
    'port' => 6379,
    'timeout' => 0,
    'password' => 'xxxxxxx',
    'dbindex' => 0,
  ),

Let me just say that for the past two days, updating to 27 has been an absolute nightmare. I’m happy that it works now, sans some strange log noise from iOS/macOS devices using Apple’s Calendar and Contacts apps (as noted in the original post, and which was alleviated by setting my log_level to 2 in the config.php), and the built-in CODE server not really working at all (hit or miss on actually being able to open a document, and you can’t save any richdocuments so it’s worthless).

As this is used primarily for Calendar and Contact sharing, that part works just fine now.