How to check if HSTS is enabled
Request the host over HTTPS and print the response headers with curl -s -o /dev/null -D - https://example.com/, then grep for strict-transport-security. HSTS is on when that line comes back carrying a non-zero max-age. No line at all means a browser that has not visited the host yet still tries plain HTTP first.
Checker offline. Follow the manual steps below, they give the same answer.
Why check this
HSTS turns the first request of a session into an HTTPS request that the browser rewrites before it leaves the machine. Run the check at staging sign-off and again after any change to the CDN, the load balancer or the vhost, because all three can drop a response header without failing a deploy. When the header is missing, a user who types the bare hostname sends one HTTP request, and any cookie without the Secure attribute rides along in clear text before the redirect lands.
Prerequisites
- curl 8.0 or later. Any TLS build works; this check needs no HTTP/2 support. See the curl manual.
- The hostname exactly as users reach it. The apex and the
wwwhost are separate HSTS hosts and can carry different policies. - MDN on Strict-Transport-Security for what each attribute of the header means.
Steps
- Step 1.
Read the header from the HTTPS response.
curl -s -o /dev/null -D - https://www.cloudflare.com/ | grep -i 'strict-transport-security'strict-transport-security: max-age=31536000; includeSubDomains - Step 2.
Run the same command against a host that sends no policy, so you know what absence looks like.
curl -s -o /dev/null -D - https://example.com/ | grep -ci 'strict-transport-security'0A count of
0is the failing result. Without-c, grep prints nothing and exits non-zero, which reads like a broken command. - Step 3.
Pull
max-ageout as a number you can compare against the policy you agreed on.curl -s -o /dev/null -D - https://developer.mozilla.org/en-US/ | grep -i 'strict-transport-security' | grep -o -E 'max-age=[0-9]+'max-age=6307200063072000 seconds is 730 days.
- Step 4.
Read the plain HTTP response and confirm the policy is not being served there instead.
curl -s -o /dev/null -D - http://www.cloudflare.com/ | grep -i -E '^HTTP/|^Location|strict-transport-security'HTTP/1.1 301 Moved Permanently Location: https://www.cloudflare.com/No policy line here is the correct result. RFC 6797 tells browsers to ignore the header on any response that did not arrive over TLS, so a config that sets it only on the HTTP vhost protects nobody.
How to read the result
| What you see | What it means | What to do |
| --- | --- | --- |
| max-age=31536000; includeSubDomains | One year, this host and every subdomain | Nothing. This is the shape to aim for. |
| max-age=300 | The policy expires five minutes after the last visit | Raise it. A short window is a rollback switch, not a policy. |
| max-age=0 | The server is clearing the stored policy | Someone left a rollback value in the config. Treat it as a release blocker. |
| No header on the HTTPS response | The host has no HSTS | The first request of every new session can still leave over HTTP. |
| includeSubDomains missing | Only this exact host is covered | Decide whether every subdomain, internal ones included, can serve HTTPS. |
Common mistakes
Thresholds
What to check next
- How to check HSTS preload status: the header alone leaves the first visit open, and preload is what closes it.
- How to check HTTP to https redirect: HSTS only helps repeat visitors, so the redirect still has to be right.
- How to check if mixed content exists on a page:
includeSubDomainsbreaks any subdomain that still serves assets over HTTP. - How to check HTTP response headers with curl: the curl flags used here, explained once for every header check.
- Security headers checker: reads this header and the rest of the set in one request.
FAQ
How to check the strict-transport-security header?
The command in step 1 is the check. -D - prints response headers to stdout and -o /dev/null throws the body away, so grep sees headers only. Any header name works in place of this one.
How to check the HSTS header on a subdomain?
Run step 1 again with the subdomain in the URL. includeSubDomains on the parent covers browser behaviour, but it does not make the subdomain send its own header, so reading the subdomain directly can return nothing.
Does a 301 to HTTPS make HSTS unnecessary?
No. The redirect is served over HTTP, so the request that triggers it is already in clear text and can be rewritten in transit. HSTS moves the decision into the browser, before any packet leaves.
What max-age is safe during a rollout?
Start at 300 seconds so a mistake ages out in five minutes, confirm no subdomain breaks, then raise it to 31536000. Lowering the value later does not reach browsers that already stored the long one.
Verified
Verified by Maks Vernycurl 8.21.0
Each output block is what the command above it printed on that date, on the host named in the step. Figures read from a live site move between runs. Compare the shape of the answer rather than the digits, and see the methodology for how a page is re-verified.
Related on this site
- Checker: security-headers CSP, HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy
- Security headers review
- TLS and certificate review
- Website launch checklist
- All security headers and tls checks
basic3 minpublished updated Maks Verny