HSTS removes the request that a redirect cannot protect
A redirect from HTTP to HTTPS protects everything except the request that asked for the redirect. HSTS closes that gap, and it is also the one header on this site that can lock you out of your own domain for a year.
The short answer
HSTS tells a browser to use HTTPS for this host for a stated period, which closes the one request a redirect cannot protect: the first plaintext one. Set max-age high, add includeSubDomains once you are certain every subdomain is HTTPS, and understand that preload is effectively one-way.
The one request a redirect cannot protect
Somebody types your domain into an address bar. There is no scheme, so the browser tries HTTP. Your server answers with a redirect to HTTPS and everything after that is encrypted. The problem is the first request: it went out in plain text, to whichever network the visitor is on, announcing which site they are about to visit.
That is enough for an attacker on the path to answer instead of your server, serve a copy of your site over HTTP, and keep the visitor there. The visitor sees no warning, because a plain HTTP page is not an error, and the padlock they were never shown is not something people notice missing.
HSTS removes the request. The header tells the browser to use HTTPS for this host for a stated period, and the browser then rewrites HTTP requests internally before anything leaves the machine. The redirect stops being involved, which is the point: a rule enforced by the client cannot be intercepted.
# a cautious start: two days, this host only
Strict-Transport-Security: max-age=172800
# the usual production value: two years, every subdomain
Strict-Transport-Security: max-age=63072000; includeSubDomains
# eligible for the browser preload list
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
# nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;One detail that catches people: the header is ignored when it arrives over HTTP. It only counts on an encrypted response, which is deliberate, since a header delivered insecurely could have been added by whoever was intercepting the connection.
max-age, subdomains, and the preload list
Three parts, in increasing order of how hard they are to undo.
- max-age is how long, in seconds, the browser should remember. It refreshes on every visit, so an active visitor never falls out of the policy. Start small, a day or two, and raise it once you are confident nothing on the host needs HTTP.
- includeSubDomains applies the policy to every subdomain, including ones that do not exist yet and ones you forgot about. This is the directive that causes incidents: an internal tool, a legacy service, a partner integration or a dashboard on a subdomain with no certificate becomes unreachable for every browser that has seen your main site.
- preload asks for your domain to be shipped inside browsers, so the policy applies before a visitor has ever been to your site. It closes the last gap, the very first visit, and it is the part to be careful about, which is the next section.
The sensible sequence is: get HTTPS working everywhere including every subdomain, set a short max-age, watch for a week, raise it, add includeSubDomains once you have inventoried your subdomains, and only then consider preload.
The lock-in nobody warns you about
HSTS is enforced by the browser, which means removing the header does not remove the policy. Every browser that has already seen it keeps enforcing for the remainder of the max-age you told it, and there is no way to reach those users to say otherwise. A two-year max-age is a two-year commitment you cannot revoke.
The retraction procedure exists and it is slow: serve max-age=0 over HTTPS and wait for every affected browser to visit and pick it up. That works for active visitors and does nothing for anyone who does not return, and it requires HTTPS to still be working, which may be the thing that broke.
Preload is worse, because the list ships inside browser releases. Removal is a request, then a wait for the next release cycle, then a wait for people to update. Months, realistically, with no way to accelerate it.
Two questions to answer before includeSubDomains, and one before preload.
Do you have a complete list of your subdomains, including the ones another team created? And does every single one of them serve HTTPS with a valid certificate today? A no to either means the directive will take something offline, and you will find out from whoever owned it.
Before preload: are you certain nobody will ever need to serve anything on this domain over HTTP for the foreseeable future? Not likely, certain. If the answer involves the word probably, set the header without preload and take the remaining ninety-five percent of the benefit.
A response header this payload does not carry
HSTS lives entirely in the response headers, and the free search returns fields read out of the document. There is no trace of the policy in the markup, which is the same reason a header-delivered directive is invisible to a markup check.
This one needs the full crawl
HSTS is a response header, and response headers are not part of the single-page payload this search returns.
The instant search on this site audits a single page, so rather than show you a verdict it cannot support, this guide sends you to the place the check actually runs.
The one-line version is in the last section of this guide, and it takes a single request.
Does this affect AI search?
No, and it is worth saying so without hedging. HSTS is a browser policy: it changes what a browser does before it makes a request. Nothing about retrieval, indexing or citation reads this header, and a site with it and a site without it are identical to anything fetching pages programmatically.
The only connection is the general one that runs through this whole pillar. A site that is correctly served over HTTPS is fetchable by clients that validate certificates strictly, and this header is part of a configuration that tends to come with that being done properly. That is correlation and not mechanism, and it would be dishonest to present it as more.
If you are looking for the security check in this group with a real effect on machine readers, it is mixed content, because a blocked script is missing content rather than a missing assurance.
Why a header that prevents an attack is only Important
Because the attack it prevents needs a precondition most visits do not have: somebody on the network path between your visitor and your server, at the moment of the first request, willing to intervene. That is a real threat on shared and hostile networks and it is not the default condition of the internet.
Nothing about your site's visibility depends on this header. Pages are crawled, indexed and ranked identically with and without it, and no result feature reads it. That keeps it out of the Critical band, which in this audit is reserved for pages being unable to compete.
It sits well above a refinement for two reasons. The gap it closes cannot be closed any other way, because a redirect is fundamentally too late. And the fix is one line of configuration with no content work attached, which makes leaving it undone a choice rather than a backlog item. The caution in this guide is about the directives, not about whether to set the header at all.
Reading the policy your site actually sends
One request tells you whether the header is there, and a second tells you whether it survives the redirect.
DOMAIN=example.com
# the header, on the secure response where it counts
curl -s -I "https://$DOMAIN/" | grep -i 'strict-transport-security'
# on the insecure response, where it is ignored. present here and absent
# above is a common misconfiguration
curl -s -I "http://$DOMAIN/" | grep -i 'strict-transport-security'
# every subdomain you know about, before you add includeSubDomains
for sub in www api docs staging shop mail; do
printf '%-24s %s\n' "$sub.$DOMAIN" \
"$(curl -s -o /dev/null -m 8 -w '%{http_code}' "https://$sub.$DOMAIN/" || echo unreachable)"
doneThe third block is the one to run before anything else. Any subdomain that does not answer over HTTPS is a subdomain that includeSubDomains will take offline, and the list of subdomains somebody set up years ago is always longer than expected.
Questions this check raises
- Why is HSTS needed if I already redirect HTTP to HTTPS?
- Because the redirect itself travels over plaintext. A visitor typing your domain makes one HTTP request before the redirect arrives, and that request can be intercepted. HSTS removes it: after the first visit, the browser upgrades the URL itself without going out to the network.
- What is a safe max-age?
- Start short, a few minutes or an hour, to confirm nothing breaks, then raise it. Two years is the common production value and it is what the preload list requires. The reason to ramp is that a long max-age with a broken certificate locks visitors out with no way to bypass it.
- Can I undo HSTS preload?
- Slowly, and that is the lock-in worth understanding before opting in. Removal from the preload list has to be requested and then ships with browser releases, which takes months. Until then every preloading browser refuses plaintext for your domain regardless of what your server sends.