What is HSTS? HTTP Strict Transport Security explained
HSTS is a small HTTP header that prevents accidental connections to HTTP, even from typed-in URLs and malicious downgrade attacks. Here's how it works, why preloading matters, and when it can lock you out of your own site.
You set up HTTPS for your site. You assume users are protected. Then someone types bank.com into their browser, gets redirected to HTTPS, and the redirect itself happens over plain HTTP — visible to a malicious network. Or someone in a hostile cafe Wi-Fi gets stripped down to HTTP without realizing.
HSTS — HTTP Strict Transport Security — fixes those gaps. It's a small browser-side enforcement layer that says: "for this domain, never use HTTP. Ever. No matter what."
If you've read our HTTPS post or certificates post, this is the third piece of the HTTPS-everywhere puzzle.
The two-line summary
HSTS is an HTTP response header that tells browsers "always use HTTPS for this domain for the next N seconds." Browsers honor it for the specified duration, even rewriting typed-in HTTP URLs to HTTPS automatically.
For high-stakes sites, HSTS is non-optional. For most sites, it's the simplest single security upgrade after enabling HTTPS itself.
How HSTS works
The mechanism is a header:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
When a browser receives this on an HTTPS response, it remembers:
- For
example.com(and, withincludeSubDomains, every subdomain), always use HTTPS. - For the next
max-ageseconds (here, 31,536,000 = one year). - The
preloadflag indicates the site has applied to be in browsers' built-in HSTS preload list (more on this below).
After the browser has seen this header once, it will:
- Rewrite any future
http://example.com/...URL tohttps://before connecting. - Refuse to connect over HTTP even if the server sends a redirect.
- Not let the user click through a certificate warning on HTTPS for that domain.
This continues for max-age seconds. Each successful HTTPS request from the browser refreshes the timer.
What HSTS prevents
Downgrade attacks
Without HSTS, a network attacker (cafe Wi-Fi, hostile ISP) can intercept the first request to example.com, see it's HTTP, and rewrite the response to keep the user on HTTP. They strip the redirect to HTTPS that the server would have sent. User stays on HTTP, attacker reads everything.
With HSTS, the browser doesn't even send the HTTP request. It silently rewrites to HTTPS before the network sees anything.
Cookie theft via mixed content
A site loaded over HTTPS may set cookies. Without HSTS, those cookies could be sent over HTTP if the user later types the URL with http:// or clicks a stale HTTP link. Anyone watching the network sees them.
HSTS forces every request to HTTPS, including the first. Cookies stay protected.
Click-through warnings
When a server's TLS certificate has problems (expired, mismatched, untrusted CA), browsers normally show a warning users can dismiss with "proceed anyway." For HSTS sites, the browser refuses entirely — no override available. This prevents users from being tricked into accepting a fake certificate.
Accidental HTTP
Users mistype URLs, click old bookmarks, follow stale links from search results, or scan QR codes that haven't been updated in years. HSTS handles all of these by forcing HTTPS.
The preload list
HSTS has a chicken-and-egg problem: the browser only learns about HSTS after its first successful HTTPS response. The first request, before the header has been seen, is still vulnerable.
The fix: a preload list built into every major browser. Sites that meet specific criteria (HTTPS, HSTS with max-age ≥ 1 year, includeSubDomains, preload) can apply at hstspreload.org. Browsers then bake the list in — every request to those domains is HTTPS-only, even before the first response.
Major sites you'd expect (google.com, facebook.com, github.com, your bank) are preloaded. So are entire TLDs like .dev, .app, .bank — every domain under those TLDs is always HTTPS-only because the TLD itself is in the list.
Once preloaded, removal is slow. Browsers update the list on release cadence; getting removed takes weeks or months.
How to deploy HSTS
If you control a website, the path is:
1. Have HTTPS working everywhere
Every URL on your domain must serve correctly over HTTPS. Including subdomains if you'll use includeSubDomains. Including any third-party services that share your domain (like a status page on status.example.com).
If anything's still on HTTP, deploying HSTS will break it.
2. Start with a short max-age
Strict-Transport-Security: max-age=300
Five minutes. Verify everything works. If something breaks, you can remove the header and the lockout clears in five minutes for any user.
3. Increase to a longer max-age
Strict-Transport-Security: max-age=86400
One day. Test for a few days. Then:
Strict-Transport-Security: max-age=31536000; includeSubDomains
One year, including subdomains.
4. Optionally preload
If you want to be on the preload list, add preload:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Then submit at hstspreload.org. Browsers ingest the new entry on their next release.
Don't preload casually. It's hard to undo. Only preload if you're certain you'll always serve HTTPS for every subdomain forever.
Common HSTS mistakes
Premature includeSubDomains
You add the directive thinking your subdomains are HTTPS-ready. Then someone discovers dev.example.com is still HTTP-only (or has a self-signed cert). Anyone with HSTS cached for example.com can no longer reach dev.example.com. Remediation requires waiting for HSTS to expire — up to a year if you preloaded.
Solution: enumerate subdomains, verify HTTPS works on all of them, then add includeSubDomains.
Using preload without committing
Once you're on the preload list, removal is genuinely slow (weeks to months). Some teams added preload as part of "best practices" without realizing the consequence, then needed to roll back HTTPS for some reason and got stuck.
Solution: don't add preload until you're certain you'll keep HTTPS forever for the domain.
Local development surprises
If myapp.example.com is HSTS-cached, but you're trying to develop locally with myapp.example.com redirected to localhost and a self-signed cert, your browser will refuse the self-signed cert with no override option.
Solution: use a different domain (e.g., myapp.example.dev or localhost.test) for local dev, not your production domain.
Forgetting to set HSTS on every response
Some servers set HSTS only on the homepage or specific routes. The browser's HSTS state updates on every received response, so this works in practice — but if a user only ever hits example.com/some-page directly and that page doesn't include the header, HSTS never engages.
Solution: configure HSTS at the load balancer or web server level so every HTTPS response includes the header automatically.
How to check a site's HSTS
curl -I https://example.com 2>/dev/null | grep -i strict-transport
If the site has HSTS, the header appears. To check preload status, visit hstspreload.org/?domain=example.com.
Browser developer tools also show HSTS state. In Chrome: chrome://net-internals/#hsts lets you query specific domains and even delete entries (useful for development).
Quick FAQ
Does HSTS apply to subdomains by default?
No — only with includeSubDomains. Without it, HSTS applies only to the exact domain that sent the header.
What happens if my certificate expires after HSTS is set? Users see an unbypassable error. They can't click through. The site is unreachable until you renew the cert. This is intentional — HSTS makes you commit to working HTTPS.
Can HSTS be disabled by a user?
Yes, in browser settings (Chrome's chrome://net-internals/#hsts allows it; Firefox has equivalent). For preload-list domains, this works for non-preloaded entries; preloaded entries can't be cleared.
Is HSTS a replacement for HTTPS? No — HSTS enforces HTTPS. You need HTTPS working first.
Should I deploy HSTS?
For nearly every public website in 2026: yes. The simple max-age=31536000; includeSubDomains configuration is rock-solid for sites that already serve HTTPS everywhere.
TL;DR
- HSTS is a header telling browsers "always use HTTPS for this domain."
- Prevents downgrade attacks, mixed-content issues, and stale HTTP links.
- The preload list bakes HSTS into browsers for high-confidence domains.
- Deploy carefully —
includeSubDomainsandpreloadare hard to undo. - For nearly every modern public site: deploy HSTS with a long max-age.
If your site is HTTPS but doesn't send the Strict-Transport-Security header, you're missing one of the easiest security upgrades available.