HSTS and Preload: Force HTTPS and Avoid Common Errors
Encrypting everything is table stakes now, but simply redirecting HTTP to HTTPS still leaves a gap on the very first visit. A browser may try plain HTTP before it learns your site’s HTTPS policy, which exposes users to downgrade and cookie-injection tricks. HSTS closes that gap after the first secure load, and the preload list can even protect the very first navigation—if you deploy it carefully.
Below we verify how HSTS works, what the preload list does, the exact header values you should ship, and how to roll out, test, and (if needed) remove preload safely. We’ll also call out common footguns like breaking forgotten subdomains or setting the header on the wrong responses.
If you’ve inherited a messy estate with stray subdomains or legacy hosts, don’t rush. HSTS is simple but unforgiving. A staged rollout, a clean DNS inventory, and targeted tests will let you force HTTPS without surprises.
Why HSTS Matters for HTTPS-Only
HSTS (HTTP Strict Transport Security) tells browsers to only use HTTPS for a host and to block click-through on certificate errors. Once a browser receives the policy in an HTTPS response, it caches the rule for the max-age period and upgrades future http:// navigations to https:// before any request leaves the device. That eliminates first-hop downgrades that a plain 301 redirect can’t fully prevent.
How HSTS Works
Browsers learn policy from the Strict-Transport-Security response header, which must be sent over HTTPS only. The core directives are max-age (seconds to remember the policy), includeSubDomains (apply to all subdomains), and the non-standard preload token used to consent to inclusion in browser preload lists. Sending the header again refreshes the timer, so policy persists as long as clients keep visiting.
Header Syntax and Safe Lifetimes
Stage lifetimes upward to reduce blast radius. Practical steps look like 5 minutes, 1 week, 1 month, then 1–2 years long-term. Ship the header on every HTTPS response, including HTTPS redirects, so the policy refreshes even when pages bounce between origins or paths. Keep it off HTTP responses; browsers ignore STS over HTTP, and it can mislead operators during audits.
Strict-Transport-Security: max-age=300
Strict-Transport-Security: max-age=604800
Strict-Transport-Security: max-age=2592000
Strict-Transport-Security: max-age=31536000; includeSubDomains
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
IncludeSubDomains and Scope
includeSubDomains extends the rule to every present and future subdomain. That is powerful and risky. If any subdomain lacks a valid certificate or only serves HTTP, clients will be hard-blocked once they cache policy from the parent. Inventory and fix these before you turn it on. Internal hosts are in scope too; if DNS resolves and the client can reach it, the browser will enforce HTTPS.
Preload: When to Use It (and When Not to)
Preloading solves the “first-visit” problem by baking your domain and a strong HSTS policy into browsers. The very first navigation is already HTTPS, so bootstrap attackers can’t force an insecure first hop. It’s valuable for public sites where users are likely to land via old http:// links or hostile networks. But preload is sticky: removal propagates with browser releases and can take many weeks, so treat it as a one-way door.
Preload Submission Requirements
To be eligible you must: serve a valid certificate on the apex, redirect HTTP to HTTPS if you listen on port 80, ensure that subdomains (especially “www” if it exists in DNS) serve HTTPS correctly, and send on the apex an HSTS header with max-age ≥ 31536000, includeSubDomains, and preload. A common compliant header is shown here.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Preload Removal, Lead Time, and Knockout Entries
If you need to exit the list, remove the preload token but keep serving a valid HSTS header, then request removal through the form. Expect the change to reach most users in roughly one to three stable release cycles; other browsers may take longer. If you must fully disable HSTS after removal has propagated, serve a “knockout” header to clear cached policy on clients. Don’t expect max-age=0 to bypass preload while you’re still listed; static preload entries remain in force until the list updates on the client.
Strict-Transport-Security: max-age=0
A Safe Rollout Plan
Map your surface first. Enumerate subdomains from DNS and inventories, then verify each resolves to an endpoint that can serve HTTPS with a valid certificate. Confirm redirects and mixed content so the HTTPS upgrade doesn’t break critical paths. Roll out in stages: add the header with a 5-minute max-age, monitor, increase to one week, then a month, then one or two years. Only after running includeSubDomains at the final lifetime without issues should you add preload and consider submitting.
Minimal Configuration Examples
Use these baseline snippets and adapt them to your environment. Ensure they are scoped to HTTPS listeners only and consistently applied at your edge/CDN.
# Nginx (HTTPS server block)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Apache (set only when HTTPS is active)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" env=HTTPS
# IIS (web.config fragment under <system.webServer>)
<httpProtocol>
<customHeaders>
<add name="Strict-Transport-Security" value="max-age=31536000; includeSubDomains" />
</customHeaders>
</httpProtocol>
Testing and Verification
Use curl to verify headers and redirects from a clean vantage point. Check the apex and key subdomains independently; HSTS is stored per host, and a browser may hit a subdomain before the parent. In devtools, confirm no mixed content and that HTTPS responses include STS even when they are redirects or 304s served from your CDN/edge.
# Expect STS header on HTTPS
curl -I https://example.com | grep -i strict-transport-security
# Expect fast 301 from HTTP to HTTPS on same host
curl -I http://example.com
# Spot-check a subdomain
curl -I https://www.example.com
Preload-Specific Checks
Before submission, double-check that www resolves, serves HTTPS, and includes the same header. Confirm that internal or legacy subdomains either have valid certificates and HTTPS listeners or are not resolvable publicly. Run the preload form’s diagnostics and resolve any failures. Plan for the lead time; expect weeks for changes to land broadly as browsers update.
Common Errors and How to Avoid Them
Breaking a forgotten subdomain is the classic failure. Avoid it by auditing DNS and hosting before you ship includeSubDomains. Another frequent mistake is setting the header only on HTML routes and not on HTTPS redirects or static asset hosts; set it consistently at your edge. Don’t send the header on HTTP responses. Avoid enabling preload prematurely; make preload a deliberate, separate change after months of stable includeSubDomains at a long max-age.
Modern Browser Behavior and What It Means
Chrome already tries HTTPS first for most typed navigations and offers HTTPS-First Mode that warns before loading insecure HTTP, with the goal of broader enablement over time. That reduces—but doesn’t remove—the value of HSTS and preload, which still provide strict behavior like blocking certificate error click-through and protecting links from non-typed entry points.
Quick Reference
Use HSTS by default on public sites, prefer 1–2 years for max-age, enable includeSubDomains only after verifying every subdomain, and consider preload only when your whole zone is permanently HTTPS and you accept slow reversibility. Test with curl and devtools, stage the rollout, and if something breaks after a client has cached policy, fix the certificate or HTTPS listener—users can’t click through errors on HSTS hosts.
