Green background with the Nginx logo and the words 'Nginx X-Frame-Options' displayed in bold green text.

How to Fix Nginx ‘Refused to Display in a Frame (X-Frame-Options: DENY)’ Error

Last updated on | 3 replies

Introduction

If Chrome (or other modern browsers) refuses to display an <iframe> served by your Nginx web server and complains about “Refused to display ‘URL’ in a frame because it set ‘X-Frame-Options’ to ‘deny'”, it means your server is instructing browsers not to allow the page to be loaded within a frame. This often happens when the X-Frame-Options header is set to DENY somewhere in your Nginx configuration.

Refused to display ‘URL’ in a frame because it set ‘X-Frame-Options’ to ‘deny’

However, you might not immediately see X-Frame-Options defined in your nginx.conf or virtual host files. Adding X-Frame-Options: SAMEORIGIN at the server level without removing existing DENY directives can cause the browser to complain about multiple headers.

Refused to display ‘URL’ in a frame because it set multiple ‘X-Frame-Options’ headers with conflicting values (‘DENY, SAME-ORIGIN’). Falling back to ‘deny’.

To fix this, you must locate and remove or modify the lines that set X-Frame-Options to DENY and replace or comment them out to avoid the conflict.

Search Nginx Config for “X-Frame-Options”

First, find out exactly where X-Frame-Options is configured. Running the command below will search the entire Nginx directory for instances of that header.

sudo grep -iRl "X-Frame-Options" /etc/nginx/

Output:

/etc/nginx/snippets/ssl-params.conf

In many cases, X-Frame-Options appears in a file such as ssl-params.conf (sometimes named ssl-dhparams.conf), but it could be elsewhere in your system. Once you find the file, open it for editing:

sudo nano /etc/nginx/snippets/ssl-params.conf

Output:

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
# disable HSTS header for now
#add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload$
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
ssl_dhparam /etc/ssl/certs/dhparam.pem;

Here, X-Frame-Options is set to DENY. This prevents <iframe> content from being displayed, even on the same domain. You can change it to SAMEORIGIN or comment it out entirely.

Changing it to SAMEORIGIN will only allow iframes from the same domain:

add_header X-Frame-Options SAMEORIGIN;

– OR –

#add_header X-Frame-Options DENY;

Save and exit (press CTRL + X, press Y, then press ENTER)

Either option removes the conflicting DENY directive. If you choose to comment it out, Nginx may default to SAMEORIGIN, but to be sure, you can explicitly set SAMEORIGIN if you need iframe functionality.

Once you’ve made the changes, test your configuration:

sudo nginx -t

Output:

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

If the syntax check passes, reload or restart Nginx:

sudo service nginx reload

After Nginx has reloaded, refresh your browser. The error about refusing to display content in a frame should now be resolved.

Understanding X-Frame-Options

The X-Frame-Options header tells the browser whether a page is allowed to load within a frame (<frame>, <iframe>, <embed>, or <object>). Websites use this header to mitigate clickjacking attacks, ensuring other sites cannot embed their content without permission.

Available directives for X-Frame-Options include:

  • X-Frame-Options: DENY — The page cannot be displayed in a frame, regardless of the domain.
  • X-Frame-Options: SAMEORIGIN — The page can only be displayed in a frame on the same origin as the server.

If you specify DENY, your page will never load in an iframe. If you specify SAMEORIGIN, iframes from the same domain will work normally, but external sites cannot embed your content.

Let me know if this helped. Follow me on Twitter, Facebook and YouTube, or 🍊 buy me a smoothie.

3 replies

Leave a reply

Your email address will not be published. Required fields are marked *

  1. Thaks alot man…really appriciate it…I was trying to solve this issue for the past 2 days. Thanks alot.

  2. Thanks for the article. You’ve used SAME-ORIGIN and SAMEORIGIN in different examples. I believe it should be the latter.

  3. Looking for this missing setting throughout nginx config files was driving me mad after getting the “conflicting values” error in chrome console. I quickly found the offending file using your method and it turned out to be a config snippet I wrote 12+ months ago [egg on face]. I take back all the profanities directed at Nginx xD