[SOLVED] Referrer-Policy and Content-Security-Policy broken on Nginx-only setup

#1

Nextcloud version: 15.0.2
Operating system and version: Debian 9 “Stretch”
Apache or nginx version:

**nginx version:** nginx/1.10.3
built with OpenSSL 1.1.0f  25 May 2017 (running with OpenSSL 1.1.0j  20 Nov 2018)
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-0TiIP5/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-dav-ext-module --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-0TiIP5/nginx-1.10.3/debian/modules/ngx_http_substitutions_filter_module

PHP version: PHP 7.0.33-0+deb9u1 (cli) (built: Dec 7 2018 11:36:49) ( NTS )
The issue you are facing:
After adding HSTS directives to nginx, I had to comment out CSP, since it breaks the instance in Firefox, and the Referrer-Policy keeps nagging me even after adding it in nginx config.
Is this the first time you’ve seen this error? (Y/N)
Config to replicate it:

upstream php-handler {
	server unix:/var/run/php/php7.0-fpm.sock;
}

server {
	root /var/www;
	index index.php;
	error_log /var/log/nginx/nextcloud-error.log;
	access_log /var/log/nginx/nextcloud-access.log combined;
	server_name cloud.intra;

	add_header X-Content-Type-Options nosniff;
	add_header X-XSS-Protection "1; mode=block";
	add_header X-Robots-Tag none;
	add_header X-Download-Options noopen;
	add_header X-Permitted-Cross-Domain-Policies none;
	add_header Referrer-Policy no-referrer always;
	add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload";
	#add_header Content-Security-Policy "default-src 'none' data: blob:; font-src 'self';
	#	connect-src 'self'; img-src 'self' data: blob:; object-src 'self';
	#	style-src 'self'; script-src 'self'; media-src 'self'; 
	#	base-uri 'self'; frame-ancestors 'self'; form-action 'self';
	#	https://cloud.intra;";
	#	REMOVED UNTIL RESOLVED
	add_header X-XSS-Protection "1; mode=block";
	add_header Referrer-Policy "no-referrer no-referrer-when-downgrade strict-origin strict-origin-when-cross-origin same-origin";
	client_max_body_size 900G;
	fastcgi_buffers 64 4K;
	gzip off;
	error_page 403 /core/templates/403.php;
	error_page 404 /core/templates/404.php;

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}
	rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
	rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json;
	location = /.well-known/carddav {
		return 301 $scheme://$host/remote.php/dav;
	}
	location = /.well-known/caldav {
		return 301 $scheme://$host/remote.php/dav;
	}
	location / {
		rewrite ^ /index.php$uri;
	}
	location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
		deny all;
	}
	location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
		deny all;
	}
	location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
		fastcgi_split_path_info ^(.+\.php)(/.*)$;
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_param PATH_INFO $fastcgi_path_info;
		fastcgi_param modHeadersAvailable true;
		fastcgi_param front_controller_active true;
		fastcgi_param PHP_VALUE "
			opcache.enable=1
			opcache.enable_cli=1
			opcache.interned_strings_buffer=8
			opcache.max_accelerated_files=10000
			opcache.memory_consumption=128
			opcache.save_comments=1
			opcache.revalidate_freq=1";
		fastcgi_pass php-handler;
		fastcgi_intercept_errors on;
		fastcgi_hide_header X-Powered-By;
	}
	location ~ ^/(?:updater|ocs-provider)(?:$|/) {
		try_files $uri/ =404;
		index index.php;
	}
	location ~* \.(?:css|js|woff|svg|gif)$ {
		try_files $uri /index.php$uri$is_args$args;
		access_log off;
	}
	location ~* \.(?:png|html|ttf|ico|jpg|jpeg)$ {
		try_files $uri /index.php$uri$is_args$args;
		access_log off;
	}

	listen [::]:443 ssl ipv6only=on;
	listen 443 ssl http2;
	ssl on;
	ssl_certificate /etc/nginx/ssl/cloud.intra/cloud_intra_bundle.crt;
	ssl_certificate_key /etc/nginx/ssl/cloud.intra/cloud.intra.key;
	ssl_session_cache shared:SSL:50m;
	ssl_session_timeout 1d;
	ssl_session_tickets off;
	ssl_prefer_server_ciphers on;
	ssl_protocols TLSv1.2;
	ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 8.8.4.4 1.1.1.1 1.0.0.1 8.8.8.8;
}
server {
	return 301 https://$host$request_uri;
	listen 80 ;
	listen [::]:80 ;
	server_name nextcloud.intra;
	error_page 404 /var/www/core/templates/404.php;
	return 404;
}

The output of your Nextcloud log in Admin > Logging:

Continuous spam about "Zend OPcache can't be temporary enabled (it may be only disabled till the end of request) at Unknown#0" - FUBAR.

The output of your config.php file in /path/to/nextcloud (make sure you remove any identifiable information!):

<?php
$CONFIG = array (
  'instanceid' => 'STRIPPED',
  'passwordsalt' => 'STRIPPED',
  'secret' => 'STRIPPED',
  'trusted_domains' => 
  array (
    0 => 'cloud.intra',
  ),
  'datadirectory' => '/var/www/data',
  'dbtype' => 'mysql',
  'version' => '15.0.2.0',
  'overwrite.cli.url' => 'https://cloud.intra',
  'dbname' => 'owncloud',
  'dbhost' => 'localhost:3306',
  'dbport' => '',
  'dbtableprefix' => 'oc_',
  'dbuser' => 'owncloud',
  'dbpassword' => 'STRIPPED',
  'installed' => true,
  'updater.release.channel' => 'production',
  'memcache.local' => '\OC\Memcache\APCu',
);

The output of your Apache/nginx/system log in /var/log/nginx: Is largely irrelevant.

#2

Bumping this.

#3

Bumping yet again.

#4

Have you already asked aunt G.? I found the following matches for your request:

https://docs.nextcloud.com/server/15/admin_manual/installation/nginx.html

#5

Not helpful. Removing and re-adding Referrer-Policy doesn’t affect the warning.

(no header in nginx)

root@cloud:~# curl -I https://cloud.intra
HTTP/2 302
server: nginx/1.10.3
date: Mon, 25 Mar 2019 12:16:08 GMT
content-type: text/html; charset=UTF-8
location: https://cloud.intra/login
set-cookie: [STRIPPED]; path=/; secure; HttpOnly
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
set-cookie: oc_sessionPassphrase=[STRIPPED]; path=/; secure; HttpOnly
content-security-policy: default-src ‘self’; script-src ‘self’ ‘unsafe-eval’ ‘nonce-[STRIPPED]’; style-src ‘self’ ‘unsafe-inline’; frame-src *; img-src * data: blob:; font-src ‘self’ data:; media-src *; connect-src *; object-src ‘none’; base-uri ‘self’;
x-frame-options: SAMEORIGIN
set-cookie: __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax
set-cookie: __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=strict
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-robots-tag: none
x-download-options: noopen
x-permitted-cross-domain-policies: none
strict-transport-security: max-age=15552000; includeSubDomains; preload
x-xss-protection: 1; mode=block

(Added Referrer-Policy block to nginx)

root@cloud:~# curl -I https://cloud.infra
HTTP/2 302
server: nginx/1.10.3
date: Mon, 25 Mar 2019 12:19:15 GMT
content-type: text/html; charset=UTF-8
location: https://cloud.infra/login
set-cookie: [STRIPPED]; path=/; secure; HttpOnly
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
set-cookie: oc_sessionPassphrase=[STRIPPED]; path=/; secure; HttpOnly
content-security-policy: default-src ‘self’; script-src ‘self’ ‘unsafe-eval’ ‘nonce-[STRIPPED]’; style-src ‘self’ ‘unsafe-inline’; frame-src *; img-src * data: blob:; font-src ‘self’ data:; media-src *; connect-src *; object-src ‘none’; base-uri ‘self’;
x-frame-options: SAMEORIGIN
set-cookie: __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax
set-cookie: __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=strict
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-robots-tag: none
x-download-options: noopen
x-permitted-cross-domain-policies: none
strict-transport-security: max-age=15552000; includeSubDomains; preload
x-xss-protection: 1; mode=block
referrer-policy: no-referrer no-referrer-when-downgrade strict-origin strict-origin-when-cross-origin same-origin

#6

Hi,

Regarding CSP: the CSP headers are added by Nextcloud automatically. No need to configure CSP in the web server config.
Writing this: you must not configure CSP manually in the configs.

Regarding the referrer header: your config differs from the advised config in the admin guide. For the “CSS” block it reads:

    # Adding the cache control header for js and css files
    # Make sure it is BELOW the PHP block
    location ~ \.(?:css|js|woff2?|svg|gif)$ {
        try_files $uri /index.php$request_uri;
        add_header Cache-Control "public, max-age=15778463";
        # Add headers to serve security related headers (It is intended to
        # have those duplicated to the ones above)
        # Before enabling Strict-Transport-Security headers please read into
        # this topic first.
        # add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
        #
        # 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 X-Content-Type-Options nosniff;
        add_header X-XSS-Protection "1; mode=block";
        add_header X-Robots-Tag none;
        add_header X-Download-Options noopen;
        add_header X-Permitted-Cross-Domain-Policies none;
        add_header Referrer-Policy no-referrer;

        # Optional: Don't log access to assets
        access_log off;
    }

It contains the referrer header as well. So the referrer header is actually defined twice within the config in different blocks.

Please remove your line:
add_header Referrer-Policy "no-referrer no-referrer-when-downgrade strict-origin strict-origin-when-cross-origin same-origin";

and fix the CSS block as described in the guide:
https://docs.nextcloud.com/server/15/admin_manual/installation/nginx.html

#7

Suggested config didn’t actually change anything.

Current nginx config

upstream php-handler {
server unix:/var/run/php/php7.0-fpm.sock;
}

server {
root /var/www;
index index.php;
error_log /var/log/nginx/nextcloud-error.log;
access_log /var/log/nginx/nextcloud-access.log combined;
server_name cloud.intra;

	add_header X-Content-Type-Options nosniff;
	add_header X-XSS-Protection "1; mode=block";
	add_header X-Robots-Tag none;
	add_header X-Download-Options noopen;
	add_header X-Permitted-Cross-Domain-Policies none;
	add_header Strict-Transport-Security "max-age=15552000; includeSubDomains; preload";
	#add_header Content-Security-Policy "default-src 'none' data: blob:; font-src 'self';
	#	connect-src 'self'; img-src 'self' data: blob:; object-src 'self';
	#	style-src 'self'; script-src 'self' 'unsafe-eval'; media-src 'self'; 
	#	base-uri 'self'; frame-ancestors 'self'; form-action 'self';
	#	https://cloud.intra;";
	add_header X-XSS-Protection "1; mode=block";
	#add_header Referrer-Policy "no-referrer no-referrer-when-downgrade strict-origin strict-origin-when-cross-origin same-origin";
	client_max_body_size 900G;
	fastcgi_buffers 64 4K;
	gzip off;
	error_page 403 /core/templates/403.php;
	error_page 404 /core/templates/404.php;

	location = /robots.txt {
		allow all;
		log_not_found off;
		access_log off;
	}
	rewrite ^/.well-known/host-meta /public.php?service=host-meta last;
	rewrite ^/.well-known/host-meta.json /public.php?service=host-meta-json;
	location = /.well-known/carddav {
		return 301 $scheme://$host/remote.php/dav;
	}
	location = /.well-known/caldav {
		return 301 $scheme://$host/remote.php/dav;
	}
	location / {
		rewrite ^ /index.php$uri;
	}
	location ~ ^/(?:build|tests|config|lib|3rdparty|templates|data)/ {
		deny all;
	}
	location ~ ^/(?:\.|autotest|occ|issue|indie|db_|console) {
		deny all;
	}
	location ~ ^/(?:index|remote|public|cron|core/ajax/update|status|ocs/v[12]|updater/.+|ocs-provider/.+|core/templates/40[34])\.php(?:$|/) {
		fastcgi_split_path_info ^(.+\.php)(/.*)$;
		include fastcgi_params;
		fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
		fastcgi_param PATH_INFO $fastcgi_path_info;
		fastcgi_param modHeadersAvailable true;
		fastcgi_param front_controller_active true;
		fastcgi_pass php-handler;
		fastcgi_intercept_errors on;
		fastcgi_hide_header X-Powered-By;
	}
	location ~ ^/(?:updater|ocs-provider)(?:$|/) {
		try_files $uri/ =404;
		index index.php;
	}
	location ~* \.(?:css|js|woff|svg|gif)$ {
		try_files $uri /index.php$request_uri;
		add_header Cache-Control "public, max-age=15778463";
		add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
		add_header X-Content-Type-Options nosniff;
		add_header X-XSS-Protection "1; mode=block";
		add_header X-Robots-Tag none;
		add_header X-Download-Options noopen;
		add_header X-Permitted-Cross-Domain-Policies none;
		add_header Referrer-Policy no-referrer;
		access_log off;
	}
	location ~* \.(?:png|html|ttf|ico|jpg|jpeg)$ {
		try_files $uri /index.php$uri$is_args$args;
		access_log off;
	}

	listen [::]:443 ssl ipv6only=on;
	listen 443 ssl http2;
	ssl on;
	ssl_certificate /etc/nginx/ssl/cloud.intra/cloud_intra_trust.crt;
	ssl_certificate_key /etc/nginx/ssl/cloud.intra/cloud.intra.key;
	ssl_session_cache shared:SSL:50m;
	ssl_session_timeout 1d;
	ssl_session_tickets off;
	ssl_prefer_server_ciphers on;
	ssl_protocols TLSv1.2;
	ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
	ssl_stapling on;
	ssl_stapling_verify on;
	resolver 8.8.4.4 1.1.1.1 1.0.0.1 8.8.8.8;
}
server {
	return 301 https://$host$request_uri;
	listen 80 ;
	listen [::]:80 ;
	server_name nextcloud.intra;
	error_page 404 /var/www/core/templates/404.php;
	return 404;
}

And here’s the head contents:

curl -I https://cloud.intra

HTTP/2 302
server: nginx/1.10.3
date: Tue, 26 Mar 2019 08:52:09 GMT
content-type: text/html; charset=UTF-8
location: https://cloud.intra/login
set-cookie: [STRIPPED]; path=/; secure; HttpOnly
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
set-cookie: oc_sessionPassphrase=[STRIPPED]; path=/; secure; HttpOnly
content-security-policy: default-src ‘self’; script-src ‘self’ ‘unsafe-eval’ ‘nonce-[STRIPPED]’; style-src ‘self’ ‘unsafe-inline’; frame-src *; img-src * data: blob:; font-src ‘self’ data:; media-src *; connect-src *; object-src ‘none’; base-uri ‘self’;
x-frame-options: SAMEORIGIN
set-cookie: __Host-nc_sameSiteCookielax=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=lax
set-cookie: __Host-nc_sameSiteCookiestrict=true; path=/; httponly;secure; expires=Fri, 31-Dec-2100 23:59:59 GMT; SameSite=strict
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
x-robots-tag: none
x-download-options: noopen
x-permitted-cross-domain-policies: none
strict-transport-security: max-age=15552000; includeSubDomains; preload
x-xss-protection: 1; mode=block

Nextcloud still gives me crap about “Referer-Policy”, and commented-out Content-Security-Policy rules break css/js/anything else but html. I can see that Nextcloud features some inbuilt CSP rules, but can’t tell if they’re restrictive enough.

#8

Quote:

	add_header X-XSS-Protection "1; mode=block";
	add_header X-Robots-Tag none;
	# ...
	add_header X-XSS-Protection "1; mode=block";

I would try to remove every header which is set twice, like
add_header X-XSS-Protection "1; mode=block";

Yes, they are :slight_smile:

#9

Rewriting config from scratch, without relying on the previous one, actually did a trick. This one works perfectly for my scenario:

current nginx conf, which passes all tests as of 15.0.7
upstream php-handler {
    server unix:/var/run/php/php7.3-fpm.sock;
}

server {
    listen 80 ;
    listen [::]:80 ;
    server_name cloud.intra;
    return 301 https://$host$request_uri;
    error_page 404 /var/www/core/templates/404.php;
    return 404;
}

server {
    listen [::]:443 ssl http2 ipv6only=on;
    listen 443 ssl http2;
    server_name cloud.intra;

    index index.php;
    error_log /var/log/nginx/nextcloud-error.log;
    access_log /var/log/nginx/nextcloud-access.log combined;

ssl_certificate /etc/nginx/ssl/cloud.intra/cloud_intra_trust.crt;
ssl_certificate_key /etc/nginx/ssl/cloud.intra/cloud.intra.key;

ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1.3 TLSv1.2; # Requires OpenSSL 1.1.1+ - https://serverfault.com/questions/962072/nginx-1-15-10-tlsv1-3-doesnt-get-applied-despite-the-config
ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA512:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:ECDH+AESGCM:ECDH+AES256:DH+AESGCM:DH+AES256:RSA+AESGCM:!aNULL:!eNULL:!LOW:!RC4:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.4.4 1.1.1.1 1.0.0.1 8.8.8.8;


error_page 403 /core/templates/403.php;
error_page 404 /core/templates/404.php;
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";
# We won't end up in browsers' lists because fuck me that's why, but it satisfies the security check-up

add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header X-Robots-Tag none;
add_header X-Download-Options noopen;
add_header X-Permitted-Cross-Domain-Policies none;
add_header Referrer-Policy no-referrer;

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

# Path to the root of installation
root /var/www;

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

location = /.well-known/carddav {
  return 301 $scheme://$host/remote.php/dav;
}
location = /.well-known/caldav {
  return 301 $scheme://$host/remote.php/dav;
}

# set max upload size
client_max_body_size 900G; # Requires consistent value all across nginx + php-fpm + nextcloud
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/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;

location / {
    rewrite ^ /index.php$request_uri;
}

location ~ ^\/(?:build|tests|config|lib|3rdparty|templates|data)\/ {
    deny all;
}
location ~ ^\/(?:\.|autotest|occ|issue|indie|db_|console) {
    deny all;
}

location ~ ^\/(?:index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+)\.php(?:$|\/) {
    fastcgi_split_path_info ^(.+?\.php)(\/.*|)$;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_param HTTPS on;

    fastcgi_param modHeadersAvailable true;
    fastcgi_param front_controller_active true;
    fastcgi_pass php-handler;
    fastcgi_intercept_errors on;
    fastcgi_request_buffering off;
}

location ~ ^\/(?:updater|oc[ms]-provider)(?:$|\/) {
    try_files $uri/ =404;
    index index.php;
}

location ~ \.(?:css|js|woff2?|svg|gif)$ {
    try_files $uri /index.php$request_uri;
    # Duplicated, but it works
    add_header Cache-Control "public, max-age=15778463";
    add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;";

    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Robots-Tag none;
    add_header X-Download-Options noopen;
    add_header X-Permitted-Cross-Domain-Policies none;
    add_header Referrer-Policy no-referrer;

    # Keep nextcloud from thrashing logs queue
    access_log off;
}

location ~ \.(?:png|html|ttf|ico|jpg|jpeg)$ {
    try_files $uri /index.php$request_uri;
    access_log off;
}

}

Marking as solved since all the security requirements from web interface, online-scan at scan.nextcloud.com and SSLLabs’ Server test were met.

1 Like