Improvements to TLS and primary domain redirects for non-static assets

tl;dr: So far, the Netlify hosting platform issued redirects from HTTP to HTTPS and redirects to the primary domain of a site for requests that reached static assets only. In coming weeks, we will revise our systems to issue these redirects for all requests to your site going forward.

What are TLS redirects?

When a user visits your site via an URL with a http:// prefix (also called scheme), the browser will start an unencrypted connection to our servers. Since our goal is to serve all traffic encrypted, we need to tell the browser to use an encrypted connection instead. This is why for all the requests without encryption, instead of serving the static file, we’re issuing a 301 redirect that goes to the same URL, but with a https scheme. The browser will then use an encrypted connection to the URL and we’ll serve the static asset.

Notes:

  • We also send a HSTS header which will make a browser automatically start on an encrypted connection the next time.
  • We only do this once you have a valid certificate provisioned for your site, so you can view the site content while your certificate is provisioning.

What are primary domain redirects?

Your Netlify site can have multiple domains that we serve the site on. Even if you just add a single custom domain, we’ll add a www/non-www variant if it’s an apex domain (not a subdomain). One of the domains on your site will be deemed the primary domain - this is the domain you intend your site to be visited on - you can change it in the domains panel in the Netlify App.

Whenever your site gets a request to one of the domains that is not your primary domain we issue a 301 redirect instead of serving the static assets. Your browser then makes another request to the URL on the primary domain. This is especially useful for SEO purposes where you don’t want your content to be served on multiple domains at once.

What is changing?

So far we’ve only been issuing these redirects for requests that reached static assets. There is not really a good reason for it, people internally and our customers have also been calling this behaviour a bug.

A specific example of what might change is if you host site.com and www.site.com on Netlify, with www.site.com set as your primary custom domain - and you use Netlify functions. Today, our CDN would usually respond to a request like http://site.com/.netlify/functions/name with your function output. After this change, we will instead respond with an HTTP 301 redirect to https://site.com/.netlify/functions/name and then another 301 redirect to https://www.site.com/netlify/functions/name (to satisfy the hsts preload standard), and finally, we would run the lambda and return its content.

Going forward, we’re consistently issuing these redirects for all requests that come into your site and need to be redirected, no matter if they are fulfilled by serving a static asset, invoking a Function or proxying to another server.

4 Likes

There still appears to be a common configuration that cannot be made compliant to the HSTS preload standard in Netlify where the apex domain redirects to a subdomain via a primary domain redirect.

If a site’s apex domain https://example.com redirects to a subdomain, e.g., https://www.example.com, then the HSTS preload standard requires the apex domain response to return the preload HSTS header: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload, where max-age is >= 31536000.

As far as I can tell, this cannot be accomplished using Netlify because the HSTS header served on primary domain redirects appears to be hardcoded to Strict-Transport-Security: max-age=31536000, which is missing the HSTS preload standard includeSubDomains and preload directives.

If my understanding above is correct, can Netlify please provide a method for primary domain redirects to be compliant with the HSTS preload standard?

You could set a custom HSTS header yourself, see the HSTS Preload section at HTTPS (SSL) | Netlify Docs.

I personally did that and my domains are preloaded just fine and the custom one will override the default HSTS header set by Netlify.

If my test is anything to go by, the redirect from www to non-www (which is automagically implemented by Netlify) does not honour the HSTS header @hartanto

# _headers
/*
  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
  # Other headers as required...

as evident in

% curl -I https://coelmay.org/
HTTP/2 200
server: Netlify
strict-transport-security: max-age=31536000; includeSubDomains; preload
# Other headers removed for brevity

versus which omits the ; includeSubDomains; preload as mentioned by @cataclysm

% curl -I https://www.coelmay.org/
HTTP/2 301
location: https://coelmay.org/
server: Netlify
strict-transport-security: max-age=31536000
x-nf-request-id: 01GEBJJ4NNRMKGMF3WYGY3KXBP
date: Sun, 02 Oct 2022 05:26:34 GMT

Do you see something different on your site(s) @hartanto? If so, can you share what you have done differently?

Hmm, you are correct. This used to work correctly I believe… It seems now Netlify strips all custom headers from the 301 redirects.

The automagic redirect sits in front of everything else: Redirects, Headers, and even Edge Functions (at least from what I established from the multiple sites have deployed as tests.)

I don’t know if there is any possibility for Netlify to allow custom headers on these redirects or not.

@coelmay and @hartanto thanks for the follow-ups and confirming what I should have made clearer in my original post. Site redirects configured using _redirects file or in the netlify.toml file can be configured to follow the HSTS preload standard. However, primary domain redirects (what @coelmay has coined automagic redirects) are not directly controlled/set by the user and do not appear to have configurable headers. Because of this, primary domain redirects cannot be configured to follow the HSTS preload standard.

Moved discussion to its own thread: Primary domain redirects do not support HSTS preload standard.