The "X-Frame-Options" HTTP header is not set to "SAMEORIGIN" security warning

I’m getting the subject matter warning on my system. I’m running a NC24 Docker (OMV) install behind an NGINX reverse proxy on a Pi4. Fairly new at this. This error message was discussed elsewhere on this forum but on older NC versions and I couldn’t make too much sense of the responses due to my lack of knowledge. I also had applicability concerns re. versions as mentioned. I was wondering what the best way was to resolve this.

Is your NC25 Docker image (not the proxy) based on Apache or NGINX (or something else)? Which Docker container image is it?

The warning means that your browser did not receive either of the following headers when it connected to your Nextcloud instance:

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN

It’s generally an indication a header option was missed in the initial web/app server setup or headers are inadvertently being mutilated at the reverse proxy.

It should already be set in most of the Docker images out there.

Purpose: Hardening and security guidance — Nextcloud latest Administration Manual latest documentation

Thanks for your response.

I’m actually running:
Nextcloud Hub 4 (26.0.1),
not 24 as originally stated. My bad.

Reverse proxy is NGINX.
I used these instructions to install nextcloud.
https://forum.openmediavault.org/index.php?thread/28216-how-to-nextcloud-with-swag-letsencrypt-using-omv-and-docker-compose/

Docker-Compose YML was:

version: "2"
services:
  nextcloud:
    image: ghcr.io/linuxserver/nextcloud
    container_name: nextcloud
    environment:
      - PUID=1001 #change PUID if needed
      - PGID=100  #change PGID if needed
      - TZ=America/Toronto #change Time Zone if needed
    volumes:
      - /SSD/appdata/nextcloud/config:/config #/srv/dev-disk-by-label-disk1 needs to be adjusted
      - /SSD/appdata/nextcloud/data:/data     #/srv/dev-disk-by-label-disk1 needs to be adjusted
    depends_on:
      - mariadb
#    ports: # uncomment this and the next line if you want to bypass the proxy
#      - 450:443
    restart: unless-stopped
  mariadb:
    image: ghcr.io/linuxserver/mariadb
    container_name: nextclouddb
    environment:
      - PUID=1000 #change PUID if needed
      - PGID=100  #change PGID if needed
      - MYSQL_ROOT_PASSWORD=xxxxxxx  #change password
      - TZ=America/Toronto #Change Time Zone if needed
    volumes:
      - /SSD/appdata/nextclouddb:/config    #/srv/dev-disk-by-label-disk1 needs to be adjusted
    restart: unless-stopped
  swag:
    image: linuxserver/swag         #swag is the replacement for letsencrypt (see link below)
    container_name: swag
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=1001 #change PUID if needed
      - PGID=100  #change PGID if needed
      - TZ=America/Toronto # change Time Zone if needed
      - URL=xxxxxxxxxxx #insert your domain name - yourdomain.url
#      - SUBDOMAINS=www,
      - VALIDATION=http
      - EMAIL=xxxxxxxx@gmail.com # define email; required to renew certificate
    volumes:
      - /SSD/appdata/swag:/config  #/srv/dev-disk-by-label-disk1 needs to be adjusted
    ports:
      - 444:443
      - 81:80
    restart: unless-stopped

/SSD/appdata/nextcloud/config/www/nextcloud/config/config.php:

    <?php
$CONFIG = array (
  'memcache.local' => '\\OC\\Memcache\\APCu',
  'datadirectory' => '/data',
  'trusted_proxies' =>
  array (
    0 => 'swag',
  ),
  'overwritewebroot' => '/nextcloud',
  'overwrite.cli.url' => 'https://xxxxxxxxx/nextcloud',
  'trusted_domains' =>
  array (
    0 => 'xxxxxxxxxxx',
  ),
  'instanceid' => 'ocelf1c7osst',
  'passwordsalt' => 'YeAADYLfb1EoafME4YXv8VhG/dokfz',
  'secret' => 'ZqvondFHxYcdUzDvuMQw+FKKnEQxwbL1DCqynrFsODJ/gXRI',
  'dbtype' => 'sqlite3',
  'version' => '26.0.1.1',
  'installed' => true,
);

/SSD/appdata/swag/nginx/ssl.conf:

## Version 2022/08/20 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/ssl.conf.sample

### Mozilla Recommendations
# generated 2022-08-05, Mozilla Guideline v5.6, nginx 1.17.7, OpenSSL 1.1.1k, intermediate configuration
# https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1k&guideline=5.6

ssl_certificate /config/keys/cert.crt;
ssl_certificate_key /config/keys/cert.key;
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;

# curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam
ssl_dhparam /config/nginx/dhparams.pem;

# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# HSTS (ngx_http_headers_module is required) (63072000 seconds)
add_header Strict-Transport-Security "max-age=63072000" always;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;

/SSD/appdata/swag/nginx/nginx.conf:

## Version 2024/04/13 - Changelog: https://github.com/linuxserver/docker-baseimage-alpine-nginx/commits/master/root/defaults/nginx/nginx.conf.sample

### Based on alpine defaults
# https://git.alpinelinux.org/aports/tree/main/nginx/nginx.conf?h=3.15-stable

user abc;

# Set number of worker processes automatically based on number of CPU cores.
include /config/nginx/worker_processes.conf;

# Enables the use of JIT for regular expressions to speed-up their processing.
pcre_jit on;

# Configures default error logger.
error_log /config/log/nginx/error.log;

# Includes files with directives to load dynamic modules.
include /etc/nginx/modules/*.conf;

# Include files with config snippets into the root context.
include /etc/nginx/conf.d/*.conf;

events {
    # The maximum number of simultaneous connections that can be opened by
    # a worker process.
    worker_connections 1024;
}

I also searched for ‘X-frame’ in config files from /SSD/appdata/nextcloud:

 find . -type f -name "*.conf" -printf '%p\n' -exec grep -n 'X-Frame' {} \;

which produced this:

./config/nginx/worker_processes.conf
./config/nginx/ssl.conf
37:#add_header X-Frame-Options "SAMEORIGIN" always;
./config/nginx/site-confs/default.conf
54:    add_header X-Frame-Options                      "SAMEORIGIN"        always;
./config/nginx/resolver.conf
./config/nginx/nginx.conf
./config/php/www2.conf

I un-commented line 37 of ssl.conf; this did not fix the problem. I re-commented the said line.

Also, my /SSD/appdata/swag/nginx/proxy-confs/nextcloud.subfolder.conf file looks like this:

## Version 2023/05/10
# make sure that your nextcloud container is named nextcloud
# make sure that nextcloud is set to work with the base url /nextcloud/
# Assuming this container is called "swag", edit your nextcloud container's config
# located at /config/www/nextcloud/config/config.php and add the following lines before the ");":
#  'trusted_proxies' => ['swag'],
#  'overwritewebroot' => '/nextcloud',
#  'overwrite.cli.url' => 'https://example.com/nextcloud',
#
# Also don't forget to add your domain name to the trusted domains array. It should look somewhat like this:
#  array (
#    0 => '192.168.0.1:444', # This line may look different on your setup, don't modify it.
#    1 => 'example.com',
#  ),

location ^~ /.well-known {
    # The rules in this block are an adaptation of the rules
    # in the Nextcloud `.htaccess` that concern `/.well-known`.

    location = /.well-known/carddav { return 301 /nextcloud/remote.php/dav/; }
    location = /.well-known/caldav { return 301 /nextcloud/remote.php/dav/; }

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

location ^~ /nextcloud/ {
    include /config/nginx/proxy.conf;
    include /config/nginx/resolver.conf;
    set $upstream_app nextcloud;
    set $upstream_port 443;
    set $upstream_proto https;
    proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    rewrite /nextcloud(.*) $1 break;
    # Uncomment X-Frame-Options directive in ssl.conf to pass security checks.
    proxy_hide_header X-Frame-Options;
    proxy_max_temp_file_size 2048m;
    proxy_set_header Range $http_range;
    proxy_set_header If-Range $http_if_range;
    proxy_ssl_session_reuse off;

and probably the last piece: /SSD/appdata/nextcloud/config/nginx/site-confs/default.conf contains:

     50     # HTTP response headers borrowed from Nextcloud `.htaccess`
     51     add_header Referrer-Policy                      "no-referrer"       always;
     52     add_header X-Content-Type-Options               "nosniff"           always;
     53     add_header X-Download-Options                   "noopen"            always;
     54     add_header X-Frame-Options                      "SAMEORIGIN"        always;
     55     add_header X-Permitted-Cross-Domain-Policies    "none"              always;
     56     add_header X-Robots-Tag                         "noindex, nofollow" always;
     57     add_header X-XSS-Protection                     "1; mode=block"     always;

Linuxserver.io just restructured all their configs significantly. I reviewed their configs (which yours presumably match).

Uncommenting that line should work. Did you restart your swag container after doing so so that the changes would be live?

I un-commented the X-Frame line in ssf.conf and re-started the swag container using

 docker exec -it d3b3ea46dbc1 nginx -s reload

(after Googling this; was not quite sure how to do this. I hope that’s the right method). In any case lo-and-behold the error message disappeared!

Earlier I simply re-booted my OMV server (Pi4) after commenting the ssl.conf X-Conf line out, and this did not resolve the issue, so likely the change was not live perhaps? Looks like re-booting the hardware platform is insufficient to ensure all changes are applied. I’m using Docker-Compose, with one YML entry so far (NextCloud). I also tried the ‘Down’ and then ‘Up’ commands and that did not work at the time.

Many thanks for your help.

1 Like

Rebooting should have been sufficient. The only thing I can think of offhand that could survive a reboot is a more obscure feature like docker checkpoints being enabled.

Another possibility is your /config not being persistent for some reason, though I don’t see anything obviously wrong in your compose that would create that situation. Might be worth doing a reboot now (again) to see if your newly modified (working) config persists just to avoid a surprise later! :slight_smile:

P.S. That command will work to kick nginx, but’s probably safest to restart the container itself: docker compose restart swag (or similar)

1 Like

Just rebooted my Pi4 to check. Still all good; No errors or warnings issued by NC. Will keep your suggested docker swag restart command handy in my notebook for future reference. Thanks again.
Ray :grinning:

1 Like