HSTS header: the settings, preload requirements and the risks
The Strict-Transport-Security value for testing, production and preload, what the preload list requires, and why removal from it takes weeks to months.
LLaunchScaler·Published ·7 min read
The HSTS header is Strict-Transport-Security, and for most production sites the right value is max-age=31536000; includeSubDomains: browsers then use HTTPS for your host and every subdomain for a year, refreshed on each visit. Use a short max-age while testing, and add preload only if you mean to join the browser preload list, which is slow to leave.
The one risk that is hard to undo is committing subdomains that cannot serve HTTPS. Everything below is ordered to avoid it.
What does the HSTS header do?
It tells a browser that has reached your site over HTTPS to use only HTTPS for that host for the next max-age seconds. The browser then rewrites every http:// URL for the host to https:// before sending anything, and it will not let a visitor click past a certificate error.
That closes the gap a redirect leaves open. With only a 301 from HTTP to HTTPS, the first request still goes out in plain text, and hstspreload.org lists what an on-path attacker can do with it: read the URL, rewrite the redirect to keep you on HTTP, and read or inject cookies. With HSTS stored, the browser never sends that plain request again.
Three rules from MDN decide whether the header works at all:
It must arrive over HTTPS. Browsers ignore a Strict-Transport-Security header sent over plain HTTP.
Every HTTPS response renews it: the expiry is reset to now plus max-age, so a policy on a site people visit never lapses.
includeSubDomains extends it to every subdomain of that host. Without it, each subdomain needs its own header.
Questions, answered
What people ask about this
01
What is the HSTS header?
HSTS is the Strict-Transport-Security response header. It tells browsers to reach your host only over HTTPS for max-age seconds, so they upgrade every http:// link to https:// and refuse to let visitors click through a certificate error.
What value should the HSTS header have at each stage?
Start with a max-age of minutes, raise it in steps while you watch for broken subdomains, and finish at one year or more. hstspreload.org publishes this ramp and says to wait out each stage's full max-age before moving on, so a mistake expires from browsers before you commit longer.
Stage
Header value
How long to stay
Testing
max-age=300; includeSubDomains
5 minutes, while you check every subdomain
Early rollout
max-age=604800; includeSubDomains
1 week
Late rollout
max-age=2592000; includeSubDomains
1 month
Production
max-age=31536000; includeSubDomains
Ongoing
Preload (optional)
max-age=63072000; includeSubDomains; preload
Ongoing, and it must stay this way
The numbers that matter to graders:
Mozilla's HTTP Observatory gives full credit from 15768000 seconds (six months), takes 10 points below that and 20 when the header is missing.
The preload list requires at least 31536000 (one year).
OWASP's cheat sheet and hstspreload.org's own example both use 63072000 (two years).
If you are not sure every subdomain works over HTTPS, drop includeSubDomains from the first stages and add it once you have checked. A header without it still protects the host that sends it.
Why must every subdomain serve HTTPS before includeSubDomains?
Because the browser applies the policy to every subdomain, whether or not you remember it exists. Any subdomain that answers only on plain HTTP, or has no valid certificate, becomes unreachable in that browser until the policy expires, and visitors cannot click through the error.
Subdomains that are easy to forget:
www, if its DNS record points somewhere without a certificate.
Old marketing tools on a CNAME, such as a help centre, status page or email-tracking domain (links.yourdomain.com) that the vendor serves only over HTTP.
Internal tools on your domain that were never public. hstspreload.org warns that preloading covers internal subdomains that are not publicly accessible.
Staging and preview hosts set up years ago.
List every record in your DNS zone, then run curl -sI https://<subdomain> against each one. Any subdomain that fails the TLS handshake or returns a certificate for a different name must be fixed, moved or deleted before you add includeSubDomains.
What does the HSTS preload list require?
The preload list is a set of domains built into Chrome, which Firefox, Safari and Edge also base their lists on. A preloaded domain gets HTTPS even on a visitor's very first request. To be accepted through hstspreload.org, a domain must meet every requirement below, on the base domain, and keep meeting them.
Serve a valid certificate.
Redirect from HTTP to HTTPS on the same host, if it listens on port 80.
Serve every subdomain over HTTPS, including www if a DNS record for it exists.
Send the HSTS header on HTTPS requests to the base domain with max-age of at least 31536000, includeSubDomains and preload.
If the HTTPS site redirects again (say from example.com to www.example.com), that redirect response must carry the HSTS header itself.
The same-host rule in step 2 is also why a redirect from http://example.com straight to https://www.example.com is a problem. The browser only learns the policy for a host it has reached over HTTPS, and the Observatory takes 5 points for an HTTP redirect that goes off-host for this reason. Redirect to https://example.com first, then to www. The www vs non-www guide and the HTTP to HTTPS redirect guide show that two-step setup.
Should you preload HSTS at all?
For most sites, no. hstspreload.org now says plainly that "While HSTS is recommended, HSTS preloading is not recommended." Chrome and Safari already upgrade HTTP navigations to HTTPS on their own, so preloading only adds protection when that upgrade fails in the presence of an active attacker.
Preload when the first-visit gap genuinely matters to you, for example a bank, a login provider or a site whose users are often on hostile networks, and you control every subdomain for years. Otherwise, a one-year max-age with includeSubDomains gives nearly all the protection with none of the lock-in.
Why is it hard to undo HSTS preload?
Because the list ships inside the browser. hstspreload.org says new entries are hardcoded into Chrome's source and can take several months to reach the stable version, and that a removal "may take 6-12 weeks to reach most Chrome users, and may take longer for other browsers." Until then, every subdomain without HTTPS is unreachable for those users.
To leave the list:
Keep serving HTTPS with a valid certificate and a valid HSTS header.
Remove the preload directive from that header. hstspreload.org treats a preloaded site that sends HSTS without preload as requesting removal.
Submit the domain at hstspreload.org/removal.
To turn HSTS off completely, send Strict-Transport-Security: max-age=0, the knockout entry.
Browsers that already stored a normal HSTS policy also keep it until their own max-age runs out, unless they see the max-age=0 header first. That is the second reason to start short: a year-long mistake takes a year to expire.
How do you set the HSTS header?
Add the header to every HTTPS response at the layer that serves them all. Some hosts already send one, so check before you add a second.
Next.js: add { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' } to headers() in next.config.js with source: '/(.*)'.
Vercel: custom domains already get Strict-Transport-Security: max-age=63072000; by default, for that host only, and HTTP is always redirected to HTTPS with a 308. Set your own header in the project config to add includeSubDomains.
Netlify: add the header to _headers in the publish directory (/* then Strict-Transport-Security: max-age=31536000; includeSubDomains) or to [[headers]] in netlify.toml. Netlify warns that adding preload "is not easily reversible."
Cloudflare: open the Edge Certificates page, select Enable HSTS under HTTP Strict Transport Security (HSTS), confirm the dialog, then set Max Age Header (disable, or 1 to 12 months), Apply HSTS policy to subdomains, Preload and No-Sniff Header. Cloudflare warns that once it is on you must not switch records from Proxied to DNS only, pause Cloudflare, move your nameservers away, redirect HTTPS to HTTP or let the certificate lapse, or visitors are locked out for the max-age.
Nginx: add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; in the HTTPS server block. The always flag makes Nginx send it on error responses too.
How do you fix "HSTS missing from HTTPS server"?
That scanner finding means an HTTPS response came back with no Strict-Transport-Security header. Add the header as above, then confirm it appears on the pages scanners actually request, not only your homepage.
Run curl -sI https://yourdomain.com | grep -i strict-transport-security and check the value.
Repeat for https://www.yourdomain.com, a static asset, and a URL that returns 404. Missing on the 404 usually means Nginx without always, or a separate error-page handler.
Repeat for each subdomain a scanner found, since includeSubDomains on the apex does not add the header to a subdomain's own responses.
In Chrome, open chrome://net-internals/#hsts and query your domain to see the policy the browser stored, or delete it while you test.
Remember the header is only half of HTTPS hygiene. The certificate behind it must stay valid, because HSTS turns an expired certificate into a hard error with no bypass; the SSL certificate expiry guide shows how to read the date and catch a failed renewal. The security headers checklist covers the other headers to send beside this one.
To check the header on your live site along with the rest of your HTTPS setup, run the free scan on LaunchScaler. It needs only your URL and no account, and its free security checks read whether HSTS is present with a max-age of at least six months, whether it is eligible for preload, whether HTTP redirects to HTTPS on the same host, and whether the certificate chain is valid and complete, among 156 checks across 6 of its 7 categories.
31536000 seconds (one year) in production. Mozilla's Observatory wants at least 15768000 (six months), the preload list requires at least 31536000, and OWASP and hstspreload.org both show 63072000 (two years) in their examples.
03
What does 'HSTS missing from HTTPS server' mean?
It is a scanner finding that your HTTPS responses carry no Strict-Transport-Security header. Add the header on every HTTPS response, and check that your server sends it on redirects and error pages too.
04
Should I submit my domain to the HSTS preload list?
Only if every subdomain, including internal ones, will serve HTTPS for the long term. hstspreload.org itself now says HSTS is recommended but preloading is not, because removal is slow and the benefit over plain HSTS is small.
05
How do I remove HSTS?
Send Strict-Transport-Security: max-age=0 over HTTPS; each browser forgets the policy the next time it sees that header. A preloaded domain must also go through the removal form, which hstspreload.org says takes 6 to 12 weeks to reach most Chrome users.
A Next.js hydration error means server HTML and the first client render differ, so React rebuilds the tree. The causes, the fix for each, and the SEO cost.