HSTS Preload
Every time you type a domain into the address bar, your browser has to pick between http:// and https:// before it sends anything.
HTTP is plain text, and HTTPS uses TLS to encrypt the connection, which means that no one between you and the server can read or tamper with it. It’ll also verify that you’re talking to the host you think you’re talking to.
Most servers will have their website hosted on http:// on port 80 and will redirect you to their https:// on port 443. This is fine, but your first request will still be sent over http://.
The first hop
Once you go to the HTTP URL, the following will occur:
sequenceDiagram
participant B as Browser
participant S as Server
B->>S: GET http://example.com
S-->>B: 301 Redirect to https://example.com
B->>S: GET https://example.com
S-->>B: 200 OK
Although this happens very quickly, someone could sniff your initial request if you’re on a public network. They could even alter the redirect to keep you on HTTP.
You can prevent this by having the browser remember that your website only uses HTTPS, so it stops trying HTTP at all.
HSTS
HSTS, also known as HTTP Strict Transport Security, is a response header that will force the user’s browser to connect to your domain over HTTPS. Once the browser has received this header from an HTTPS response, it’ll store it for max-age seconds.
The flow of requests would then look something like this:
sequenceDiagram
participant B as Browser
participant S as Server
Note over B: HSTS policy already cached
B->>S: GET https://example.com
S-->>B: 200 OK
Any http:// links to your domain will be rewritten to https:// before the browser sends the request. If you look at Chrome’s devtools, you’ll see a 307 redirect with 0 bytes transferred, because the browser is doing this before it makes any network request:

Since the plaintext request never leaves the browser, it can’t be altered by an attacker. This will prevent most downgrade attacks, but only once a user has visited your site and their browser has been given the HSTS header.
Preload
There’s a solution for this called HSTS preload. Chrome maintains a list of websites that should only be accessed over HTTPS, and other browsers use this list to build their preload lists. If your website is on this list, the browser will automatically go from http://example.com to https://example.com before sending anything, just as if the user had visited your site before.
Only websites that include the includeSubDomains directive in their header can be added to the preload list. This means that if you have example.com preloaded, then blog.example.com would also be forced to use HTTPS from the first visit.
Preload is less of a big deal now. Chrome has been trying HTTPS by default since v115 for all navigations (no HSTS required). It’ll fall back to HTTP if that fails, though, and an attacker who can block your HTTPS request can force that fallback. If a domain is preloaded, it’ll never fall back.
Requirements
Your site must meet these requirements to be preloaded:
- serve a valid TLS certificate
- redirect
HTTPtoHTTPSon the same host, if port80is open - serve all subdomains over
HTTPS - send the
HSTSheader from the base domain with amax-ageof at least one year, plusincludeSubDomainsandpreload
Here is an example of a valid header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Submit your domain to hstspreload.org once you have it enabled.
There are two requirements that people tend to overlook:
- “All subdomains” really means all of them. That includes
wwwif it has a DNS record, and internal hosts that aren’t reachable from the internet. - If your
HTTPSsite redirects, like fromexample.comtowww.example.com, the redirect response needs theHSTSheader too.
I’d say don’t go to a year right away. Start the max-age at a few minutes, ramp it up in stages, and ensure all subdomains can use HTTPS before increasing it to the preload value.
You can always request to be removed from the list later, but it’ll take months for that to propagate to users’ browsers. So only add your domain if you know it and all your subdomains can stay on HTTPS for good.