HTTP Strict Transport Security for NGINX and Apache

David Oravsky55 VIEWS
Last Updated - May 3, 2019
Summary : This tutorial will show you how to set up HSTS in NGINX and Apache. It has been tested with NGINX 1.1.19 and Apache 2.2.22 on Ubuntu 12.04, Debian 6 & 7 and CentOS 6. However, these are just the referenced versions and it should work on other distributions as well.


Quoting the Mozilla Developer Network, HTTP Strict Transport Security (HSTS) is a security policy that is needed to protect secure HTTPS websites from downgrade attacks.  HSTS also helps protect against cookie hijacking.  This allows web servers to declare that web browsers should interact with it only through secure HTTPS connections, and never via the insecure HTTP protocol. 

An example scenario:

You log into a free WiFi access point at the airport and start browsing the web, visiting your online banking service to check your balance and pay several bills.  Unfortunately, the access point you use is a hacker's laptop, and it intercepts your initial HTTP request and redirects you to a clone of your bank's site instead of the real one.  Now your personal data is open to the hacker.

Strict Transport Security resolves this problem; if you've accessed your bank's web site once via HTTPS, and the bank's web site uses Strict Transport Security, your browser will automatically use only HTTPS, which prevents hackers from carrying out this sort of man-in-the-middle attack.

NOTE:  HSTS does not work if you've never visited the website before, the website must first tell you it is only HTTPS.

How Does HSTS Work?

When a compatible HSTS browser contacts a web server with HSTS support, it searches for a special HTTP header.  This header states that the web client should only communicate with the server through an HTTPS connection.

In addition, there is a max-age value associated with the header, which allows the browser to know that the server administrator ensures that access to the site is possible only through HTTPS, at least during this time.  This max-age value should be long lasting. At minimum of 6 months is recommended, but several years are possible.

Once the web browser has visited the site once and received the header, it will remember that access to the site should be done only via HTTPS during the period of the maximum age.  This value is reset each time a site is accessed.


An obvious advantage of “forcing” a client to use HTTPS directly is to reduce the risk of transmitting any sensitive information through a protocol that can be used for tracking.  In addition, it improves performance by eliminating one redirect response (301/302).  Another advantage is to force the use of a secure connection and to refuse the client if this cannot be guaranteed (for example, the expiration date or self-signed certificate has expired).

Important Notes

The HSTS header should only be sent over a secure channel, so HTTP responses should not include them.


Within the headers, the max-age determines which period the site is willing to accept only HTTPS (31536000 in the examples are 12 months).  Usually the amount of time is less important.  This is since in any case there is a tendency to use HTTPS to ensure privacy and data protection.

Top level domain (TLD)

In addition, make sure the top-level domain itself is also configured correctly for HSTS.  This reduces attacks on base sub-domain names.


Please note that preload directive will have a semi-permanent effect.  It is important that you understand what you are doing and understand what the preload directive means. 

When you first connect to an HSTS host (usually a publicly accessible website), the browser does not know whether to use a secure connection, since it never received the HSTS header from that host.  Therefore, an active network attacker can prevent the browser from establishing a secure connection (and, even worse, the user may never understand that something is wrong).  To mitigate this attack, Google Chrome, and then Safari and Firefox, added a list of hosts that, by default, use HSTS, commonly called HSTS preload lists.  If your HTTPS configuration is incorrect, broken, or you don't want to use HTTPS anymore, you will have problems.  See also this article.

In the configuration below, the preload directive has been removed, since most people seem to mess it up.

If you still want to use preload, just add it to the header after the semi-colon.

Apache - Configuration

Edit your Apache configuration file (/etc/apache2/sites-enabled/website.conf and /etc/apache2/httpd.conf) and add the following to your VirtualHost:

# Optionally load the headers module:
LoadModule headers_module modules/

Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"

Now your site will set a header every time someone visits, with a two-year expiration date (in seconds).  This sets it at every visit. So tomorrow, it will say two years again.

You must only set it on the HTTPS vhost, it cannot be in the http vhost.

To redirect your visitors to the HTTPS version of your website, use the following configuration:

<VirtualHost *:80>
Redirect permanent /

If you only redirect, you don’t even need a document root.

You can also use modrewritehowever, the above method is simpler and safer Using modrewrite below redirects the user to the page they were visiting over https, the above config just redirects to /:

<VirtualHost *:80>
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

And don't forget to restart Apache.

NGINX - Configuration

NGINX is even shorter with its config.  Add this in the server block for your HTTPS configuration:

add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; ";

Don't forget to restart NGINX.

X-Frame-Options Header

The last tip I give you is the X-Frame-Options header, which you can add to your HTTPS site to make sure it is not embedded in a frame or iframe.  This avoids click-jacking and can be useful for HTTPS websites.  Again, quoting the Mozilla Developer Network, the X-Frame-Options HTTP response header can be used to specify whether to allow the browser to display the page in a `<frame>` or `<iframe>`. Sites can use this to avoid click-jacking attacks, ensuring that their content is not embedded in other sites.

You can change DENY to SAMEORIGIN or ALLOW-FROM URI, see the Mozilla link above for more information about this (or the RFC).

X-Frame-Options for Apache

As above, add this to the Apache configuration file:

Header always set X-Frame-Options DENY

X-Frame-Options for NGINX

Yet again, in the server block:

add_header X-Frame-Options "DENY";

Testing your Site

Once a client is presented with an HSTS policy, it caches information for a specified max-age period. During this period, the browser refuses to access the web service over unencrypted HTTP and refuses to provide exceptions for certificate errors (if the site previously provided a valid, trusted certificate).

If you specify the includeSubDomains parameter for the HSTS policy, these restrictions will also apply to all sub-domains of the current domain.

It is very difficult to abandon the HSTS policy for removing the HTTPS version of a website or service. When you are testing HSTS, use a very short max-age timeout and make sure that you feel comfortable with the consequences and the obligation to maintain the HTTPS version of your site.

When you first turn on your HSTS policy, keep max-age small and increase it only when you are sure of it.

Test your configuration using the SSL Labs Test Site. The output will tell you if you have everything configured correctly.


While unsafe HTTP content can be delivered for a variety of reasons, HSTS helps eliminate this risk, leaving attackers unable to intercept the connection. Securing a website is a difficult task, and I hope that you will add a level of security using the above headings.

If you any questions or thoughts on the tutorial, feel free to reach out in the comments below.

If you like this article, consider sponsoring us by trying out a Digital Ocean VPS. With this link you'll get $100 credit for 60 days.

Additional Reading: