I recently ran my site through securityheaders.com and realized I was missing a few useful headers. Here is the set I ended up adding to my Nginx config.

The headers

add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self'; font-src 'self';" always;

What each one does:

  • X-Content-Type-Options prevents browsers from guessing the MIME type of a response. Without this, a browser might interpret a text file as HTML and execute scripts in it.
  • X-Frame-Options prevents your site from being embedded in an iframe on another domain. This mitigates clickjacking attacks.
  • Referrer-Policy controls how much referrer information is sent when navigating away from your site. strict-origin-when-cross-origin is a sensible default.
  • Permissions-Policy explicitly disables browser features your site does not use. A static blog has no need for camera or microphone access.
  • Content-Security-Policy restricts where resources can be loaded from. The policy above only allows resources from the same origin, which is exactly right for a self-contained static site with no external dependencies.

The always keyword

Note the always parameter on each header. Without it, Nginx only adds headers to successful responses (2xx and 3xx). With always, headers are included on error pages too. This matters because error pages are also potential attack vectors.

Placement

These go in the server block of your Nginx site configuration. If you add them in a location block instead, be aware that Nginx does not inherit add_header directives from parent blocks — you would need to repeat them in every location block.

Verifying

After reloading Nginx (nginx -t && systemctl reload nginx), you can check the headers with curl:

curl -sI https://packetlog.org | grep -iE "x-content|x-frame|referrer|permissions|content-security"

These headers are low-effort and cost nothing in terms of performance. There is no reason not to set them.