HSTS is powerful and unforgiving. Once a browser caches the policy, it enforces HTTPS-only for the max-age duration — no way to override until it expires. Deploy in stages.
Prerequisites
- HTTPS working reliably on your domain (valid cert, no mixed-content issues)
- If you plan to use
includeSubDomains: every subdomain also serves valid HTTPS - Access to your web server config, CDN, or reverse proxy
Stage 1 — Verify HTTPS Is Solid
Before HSTS, confirm:
- Every path on your domain serves valid HTTPS
- Every subdomain used in production serves valid HTTPS
- No hardcoded HTTP references in your app, in emails, or in third-party integrations
- Cert renewal automation works (see how to renew Let’s Encrypt)
Check with the SSL certificate checker.
Stage 2 — Short max-age (Test)
Start with a low max-age:
Strict-Transport-Security: max-age=300
- 300 seconds = 5 minutes of enforcement
- If something breaks, browsers un-cache within minutes
Deploy this for 24-48 hours. Verify:
- HTTPS still works everywhere
- No user reports of “site broken”
Stage 3 — Medium max-age (One Week)
Bump to:
Strict-Transport-Security: max-age=604800
- 604800 seconds = 7 days
- Any breakage now takes 7 days to expire for cached users
Wait a week. Watch for issues.
Stage 4 — Full max-age (One Year+)
If Stage 3 is clean:
Strict-Transport-Security: max-age=31536000
- 31536000 seconds = 1 year
- Google’s recommended baseline
Stage 5 — includeSubDomains (Optional)
Only do this after auditing every subdomain. Once enabled and cached, every subdomain in scope is HTTPS-only — no override.
Strict-Transport-Security: max-age=31536000; includeSubDomains
Common gotcha: a legacy dev.yourdomain.com or internal intranet.yourdomain.com that serves HTTP. includeSubDomains breaks it for every user who’s already cached the policy.
Stage 6 — Preload (Optional)
For HSTS Preload — Chrome/Firefox/Safari/Edge ship a hard-coded list of HSTS-enforced domains:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
max-age=63072000(2 years) — required by the preload list- Submit at
hstspreload.org
Preloaded means every visitor gets HSTS enforcement from the very first visit. It’s also very hard to remove — plan for permanence.
Verification
After each stage, verify with the security headers checker. Expected: HSTS header present with the correct max-age.
Test the browser’s cached policy: navigate to chrome://net-internals/#hsts (Chrome) or about:config → security.stricttransportsecurity (Firefox).
Common Miss
- Jumping straight to
max-age=31536000; includeSubDomains; preloadon day one — cached for years, subdomain breakage lasts forever - Enabling
includeSubDomainswhen internal subdomains still serve HTTP — breaks internal tools - Setting
max-age=0to disable — cached users keep the policy until expiry; you can’t force flush - Preloading and later needing to remove — the removal process takes months and is not guaranteed
Follow up with how to write a Content Security Policy for the next layer.
Related
Check the HSTS glossary entry, read the HTTP security headers explainer, and see how to write a Content Security Policy.