Report this

What is the reason for this report?

HSTS (with Nginx) does not work properly

Posted on January 17, 2018

I want to add HSTS to my Mezzanine 4.2.3 site. Using Nginx 1.10.3 and Ubuntu 16.04.

If I take add_header Strict-Transport-Security "max-age=60; includeSubDomains" always; out of the code below, the site works well, and visitors are always sent over to HTTPS.

However, adding the HSTS code makes it work intermittently. Sometimes it goes to HTTPS, but mostly it breaks and says the site is insecure.

server {
listen 80;
server_name *.example.com;
location / {
    rewrite ^ https://example.com;
    }
}

server {
server_name <droplet ip address> example.com;
listen 443 ssl;

# managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

# Redirect non-https traffic to https
if ($scheme != "https") {
    return 301 https://$host$request_uri;
} # managed by Certbot

add_header Strict-Transport-Security "max-age=60; includeSubDomains" always;

location = /favicon.ico { access_log off; log_not_found off; }
location /static/ {
    root /home/example;
}

location / {
    include proxy_params;
    proxy_pass http://unix:/home/example/example.sock;
}
}

I’ve read Adding HSTS to nginx config and Best nginx configuration for improved security(and performance), as well as Nginx’s own HTTP Strict Transport Security (HSTS) and NGINX.

Based on these articles, I think the code is ok. But I’m not sure. I’ve got the redirect to HTTPS (handled by Certbot), the SSL cert, and the HSTS header.

What have I missed?



This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Hello,

In case someone stumbles upon this question, It seems that the issue is with the configuration of the HSTS header. The HSTS header is sent to the browser on the first request and instructs the browser to only access the website over HTTPS for the duration specified in the header. In your configuration, the max-age of the HSTS header is set to 60 seconds, which is a very short duration. This means that after 60 seconds, the browser will no longer enforce HTTPS and will allow HTTP access to the website.

To fix this issue, you should increase the duration of the max-age parameter in the HSTS header to a longer period, such as 31536000 seconds (1 year). You can also consider adding the preload parameter to the header, which will include your website in the HSTS preload list maintained by major browsers. This will ensure that even new visitors to your website will always access it over HTTPS, even if they have never visited your website before.

Here is the updated configuration with the changes to the HSTS header:

server {
    listen 80;
    server_name *.example.com;
    return 301 https://example.com$request_uri;
}

server {
    server_name <droplet ip address> example.com;
    listen 443 ssl http2;

    # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/example;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/example/example.sock;
    }
}

Note that I also updated the configuration to include the http2 parameter on the SSL listener, which enables HTTP/2 support. This should improve the performance of your website.

Hello,

In case someone stumbles upon this question, It seems that the issue is with the configuration of the HSTS header. The HSTS header is sent to the browser on the first request and instructs the browser to only access the website over HTTPS for the duration specified in the header. In your configuration, the max-age of the HSTS header is set to 60 seconds, which is a very short duration. This means that after 60 seconds, the browser will no longer enforce HTTPS and will allow HTTP access to the website.

To fix this issue, you should increase the duration of the max-age parameter in the HSTS header to a longer period, such as 31536000 seconds (1 year). You can also consider adding the preload parameter to the header, which will include your website in the HSTS preload list maintained by major browsers. This will ensure that even new visitors to your website will always access it over HTTPS, even if they have never visited your website before.

Here is the updated configuration with the changes to the HSTS header:

server {
    listen 80;
    server_name *.example.com;
    return 301 https://example.com$request_uri;
}

server {
    server_name <droplet ip address> example.com;
    listen 443 ssl http2;

    # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot

    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/example;
    }

    location / {
        include proxy_params;
        proxy_pass http://unix:/home/example/example.sock;
    }
}

Note that I also updated the configuration to include the http2 parameter on the SSL listener, which enables HTTP/2 support. This should improve the performance of your website.

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.