How HSTS actually works, and when to use preload
Published May 27, 2026 · ~5 min read
HSTS closes a small but real attack window. Without it, the first request from a new visitor might go out over plain HTTP, and an attacker on the same network can intercept that request before the server has a chance to redirect to HTTPS. HSTS solves this by telling the browser to do the redirect itself, before any request leaves the device. The browser remembers the instruction for the duration you specify, then enforces it on every subsequent visit.
This is what the header looks like in its simplest form:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadThere are three things worth understanding: what each directive does, what gotchas exist, and when (if ever) to add the site to a browser preload list.
The three directives
max-age is how long the browser should remember the instruction, in seconds. The value above is one year. Browsers reset this counter on every request that includes the header, so a continuously-served HSTS header keeps the window rolling forward. The minimum value that gets you any meaningful protection is around six months (15,552,000 seconds). The preload list requires one year.
includeSubDomains extends the policy to every subdomain of the host. If you set this on example.com, then api.example.com, staging.example.com, and internal.example.com all become HTTPS-only too. This is usually what you want, but it can break things if any subdomain is HTTP-only or uses a self-signed certificate.
preload is a flag that opts your domain into a hard-coded list shipped with every major browser. Once your domain is on that list, the HSTS rule is enforced from the very first visit by anyone, even before they have ever seen your server. The catch is that getting onto the list is easy and getting off is slow.
The first-visit problem
HSTS only works after the browser has seen the header at least once. The first time a new visitor types your hostname into their address bar, they might end up on an HTTP URL, and an attacker on the same network has a brief window to intercept that request and serve them a fake HTTPS page (or no HTTPS at all).
This is the gap that the preload list closes. The list is compiled into Chrome, Firefox, Safari, and Edge, so a preloaded domain is HTTPS-only from the very first connection any of those browsers makes, on any device.
When to use preload (and when not to)
Use preload when:
- Your domain and every subdomain has been HTTPS-only for at least a few months.
- You have automated certificate renewal that has worked reliably.
- You are confident no current or future internal tool needs to be served over HTTP.
Do not use preload when:
- You sometimes serve HTTP for a particular subdomain (legacy device firmware, network printers, an internal status page).
- Your DNS or hosting setup is in flux.
- You are running a personal or experimental project and just want HSTS coverage on the apex.
Removal from the preload list is a separate request and can take months to roll out as browsers update. Until then, browsers will refuse to load your domain over HTTP for any reason, including if you intentionally turn HTTPS off for testing.
How to verify it
Once the header is set, test it from a clean session:
curl -sI https://yourdomain.com/ | grep -i strict-transportYou should see the header with the values you configured. Then check what the browser actually stored by visiting chrome://net-internals/#hsts in Chrome and querying your domain.
If you are submitting to the preload list, the validator at hstspreload.org will check that all your subdomains satisfy the requirements before accepting the submission.
Common mistakes
A few patterns come up over and over:
- Setting
max-age=0to "turn off HSTS" but not realizing the directive only resets browsers that visit while it is being served. Browsers that visited during the long-max-age window remember the old setting until that age expires. - Adding
includeSubDomainswithout auditing every subdomain. If one of them serves HTTP, it suddenly stops working for any user whose browser has seen the parent header. - Adding
preloadto the header but never submitting to the preload list. The directive on its own does nothing. - Setting the header on a plain-HTTP redirect response. Browsers are required to ignore HSTS headers received over HTTP, so the directive only counts when it arrives over HTTPS.
HSTS is one of the cheapest security wins available. The complexity is entirely in the decision about preload, not in deploying the header itself.