Skip to content

🔒 HSTS Preload Eligibility Check

hstspreload.org submission criteria (HSTS header, max-age ≥ 1 year, includeSubDomains, preload, HTTP→HTTPS redirect, HTTPS on the www subdomain) are checked automatically.

100% Free No signup Server-side No logs / DB Rate-limited 5 languages Dark mode

⚠️ Requests are made from DevLab servers. Private IP addresses and localhost are not allowed.

📖 What this check tells you

This check connects over HTTPS, reads the Strict-Transport-Security header and judges whether max-age, includeSubDomains and preload satisfy the preload list requirements. Keep in mind that HSTS only protects visits after the first one: nothing is enforced until the browser has received the header, so that initial cleartext request can still be intercepted. Closing that gap is exactly what the preload list is for.

Item What it means How to fix it
max-age is too short max-age tells the browser how many seconds to keep forcing HTTPS. Applying to the preload list requires at least 31536000 (one year), and 63072000 (two years) is the common recommendation. Set it short and users fall back to a state where plaintext is possible again once it lapses. Do not jump straight to two years — step it up as 300, then 86400, 2592000 and finally 63072000. If you discover an HTTPS problem along the way, a short value expires quickly and limits the damage. Move to the final value only once every subresource is confirmed to load over HTTPS.
includeSubDomains added carelessly This directive forces HTTPS on every subdomain, immediately and without exception. If legacy.example.com, an internal tool or a click-tracking host is still on HTTP, those become unreachable at once — and because the rule is remembered in each user browser, rolling the server back does not fix it until max-age expires. Before enabling it, open the DNS zone, list every A and CNAME, and confirm each one loads over HTTPS. A single wildcard certificate usually covers them, but a wildcard does not match multi-level names such as a.b.example.com, which need their own certificate.
The header seems to be missing Two causes dominate. (1) It is set on the HTTP (cleartext) response. RFC 6797 requires HSTS on a plaintext response to be ignored, so putting it on the 301 from HTTP to HTTPS achieves nothing. (2) nginx add_header inheritance was cancelled: a single add_header inside a nested location block discards every add_header from the enclosing block for that location. Set it on the HTTPS 200 response. On nginx add the always flag (add_header … always;) so it appears on error responses too, and either copy the same line into every location block that has its own add_header, or pull a shared file in with include.

Once HSTS is on, an expired or mismatched certificate leaves users with no way to click through the warning. That is the specification working as intended, which makes monitoring your certificate auto-renewal all the more important. If you enable it by accident on a development machine, Chrome lets you clear a single host under chrome://net-internals/#hsts via Delete domain security policies.