Securing NGINX - Fedora/RedHat

Step 3d - Creating & Enabling Security Headers - Mandatory Step!!!

Creating & Enabling Security Headers

Security Headers seems to be one of the most skipped steps in just about every configuration out there. We have listed the minimum security headers which should be included in every instance of NGINX. Security Headers (Help prevent sniffing and manipulating our content by someone else) is a whole topic to itself on how to control the connection with clients. Not to mention, what we could possibly do to anyone using header manipulation to inject all sorts of fun. NGINX module and header manipulation is truly an art form that seemingly very few people understand. This is where the majority of the security work and tweaking comes into play in order to stay ahead of the curve. There are some lovely options for headers and how to use them.

We are using headers to deal with reporting and things like:

  • Clickjacking Attack
  • Only using secure Cookies
  • Not allow for framing options outside of our domain (X-Frame-Options)
  • Only allowing JavaScript, Applications, PHP, HTML, images, movies, etc. to be run from the same domain only
  • X-XSS-Protection
  • X-Content-Security-Policy
  • Remove the ETag
  • Not allow sniffing of our domain assets for downloading or uploading an executable file
  • Setup Cache Control
  • Enable and disable web platform features
  • Leakage of referrer data over insecure connections
  • Network error logging

Header Syntax usage: add_header name value [always];

The below chart breaks down the top million requested websites - Scott Helme performed this very interesting study about the lack of Security Header use in the top million requested website's. The results for Februay 2019 came in. Whilst things didn't look too great in the first scan back in 2016, the rate of improvement being shown is incredible! These numbers are still a long way from where we'd like to see them but all of the metrics are showing considerable progress. Scott Helme Security Headers Test-

Scott Helme Stat Table

Image courtsey of

We do not recommend using security headers as a global configuration and will not show an alternative way of using them.

Adding Headers to the NGINX Web site config file

nano /etc/NGINX/sites-available/EXAMPLE_com_ssl.conf

Add Security Headers <--Add the sections in blue to the file

server {

 etag off;
        proxy_cookie_path / "/; HTTPOnly:Secure";
        add_header X-Content-Type-Options nosniff always;
        add_header X-XSS-Protection "1; mode=block; report=" always;
        add_header Referrer-Policy no-referrer-when-downgrade always;
        add_header Permissions-Policy geolocation=() always;
        add_header NEL "{\"Report-To\":\"default\",\"max_age\":31536000,\"include_subdomains\":true}" always;
        add_header Expect-CT enforce,max-age=30,report-uri="" always;
        add_header X-Frame-Options DENY always;
        add_header Cache-Control "public, max-age=31536000" always;
        add_header MyHeader "Feel safe Zombie headers in use!!! It took %D microseconds to serve this request on Epoch Time %t microseconds" always;
        add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
        add_header Report-To "{\"group\":\"default\",\"max_age\":31536000,\"endpoints\":[{\"url\":\"\"}],\"include_subdomains\":true}" always;
        add_header Content-Security-Policy "script-src 'self'; style-src 'self'; img-src 'self'; font-src 'self'; connect-src 'self'; media-src 'self'; object-src 'self'; worker-src 'none'; frame-ancestors 'none'; form-action 'self'; report-uri; report-to default" always;
        add_header X-Permitted-Cross-Domain-Policies none always;

Close and exit the file

ctrl + o   (Save)
ctrl + x   (Exit)

Restart NGINX

systemctl restart nginx

Zombie Security Headers Results

Zombie Security Headers A+
Zombie Security Headers

Test results Febraury 2020 - Image courtesy of