You added the headers, reloaded, and a scanner still says they’re missing. Almost always one of these:
1. Nginx: add_header inheritance
add_header directives are not inherited into a context that defines its own. If you set
headers at server level but also have an add_header inside a location, that location loses
all the server-level headers.
server {
add_header X-Frame-Options "SAMEORIGIN" always; # set here
location /api/ {
add_header Cache-Control "no-store" always; # this WIPES X-Frame-Options here!
}
}
Fix: repeat the security headers inside every location that adds its own, or use the
headers-more module’s more_set_headers (which does inherit).
2. Missing the always flag (Nginx)
Without always, add_header only applies to a short list of 2xx/3xx codes — so error pages
(401, 403, 404, 5xx) ship without your headers.
add_header X-Content-Type-Options "nosniff" always;
3. Duplicate headers from app + proxy
If your app (Express, PHP, Rails…) and your reverse proxy both set a header, the client sees it twice, which some checks treat as invalid. Pick one layer. To strip an app header at the proxy:
proxy_hide_header X-Frame-Options; # then re-add your own
add_header X-Frame-Options "SAMEORIGIN" always;
Apache equivalent:
Header unset X-Frame-Options
Header always set X-Frame-Options "SAMEORIGIN"
4. Editing the wrong file / not reloading
.htaccess needs AllowOverride on; vhost edits need a reload. Always reload after changes:
sudo nginx -t && sudo systemctl reload nginx
# or
sudo apachectl configtest && sudo systemctl reload apache2
5. Debug: see what’s really sent
curl -sI https://yourdomain.com # all response headers
curl -sI https://yourdomain.com/missing # check an ERROR page too
Rule of thumb: test an error URL, not just the homepage. Headers that are present on / but
missing on a 404 mean you forgot always (Nginx) or the error document bypasses your config.