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.
Thaks alot man…really appriciate it…I was trying to solve this issue for the past 2 days. Thanks alot.
Thanks for the article. You’ve used SAME-ORIGIN and SAMEORIGIN in different examples. I believe it should be the latter.
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