You submitted your domain to hstspreload.org because a security checklist told you to. Weeks later it shipped inside Chrome and Firefox. Now you need to roll back: maybe you’re selling the domain, maybe a cert lapsed and you need temporary HTTP, maybe you’re decommissioning. You delete the Strict-Transport-Security header. Browsers keep forcing HTTPS for your domain and every subdomain (because preload requires includeSubDomains). That is by design: preload bakes your domain into the browser binary, so server-side changes alone do nothing.
Fastest fix (90% of cases): you almost certainly don’t need to remove preload at all. Most “HSTS preload stuck” tickets are really “the cert expired and we panicked.” Reissue a valid certificate over HTTPS and the symptom disappears in minutes. Only pursue removal from the preload list if you genuinely need plain HTTP on the apex or a subdomain forever, and even then expect a months-long tail.
Which bucket are you in?
Pick the row that matches your symptom before touching anything. The right action is rarely “remove from the preload list.”
| Symptom | Real cause | Fastest fix |
|---|---|---|
NET::ERR_CERT_DATE_INVALID, no “proceed” button | Cert expired on a preloaded domain | Reissue the cert (Step 1). No removal needed. |
New subdomain shows ERR_SSL_PROTOCOL_ERROR before you finish typing | includeSubDomains forces HTTPS on it | Put a valid cert on the subdomain, or move it off the preloaded apex (Step 2). |
Internal staging NET::ERR_CERT_AUTHORITY_INVALID, no bypass | Self-signed cert under a preloaded parent | Use a separate, non-preloaded domain for staging (Step 2). |
| Site fails only on hotel/airport Wi-Fi | Captive portal can’t intercept HTTPS | Tell users to open http://neverssl.com first; not a domain problem. |
| You’re selling/decommissioning the domain | New owner can’t serve HTTP | Submit removal and wait out the rollout (Steps 3-4 and 6). |
Common causes
Ordered by how often each shows up in postmortems.
1. Subdomain you forgot about now needs HTTP
You submitted preload covering includeSubDomains. Months later someone spins up legacy.yourdomain.com on a service that only does HTTP (an old IoT panel, a printer admin, a CI artifact server). Browsers refuse to load it over HTTP forever, because the parent’s preload entry forces HTTPS on everything beneath it.
How to spot it: The new subdomain returns ERR_SSL_PROTOCOL_ERROR or “This site can’t be reached” in Chrome before the user even types http:// — Chrome rewrites the scheme to HTTPS first.
2. Cert expired and you can’t issue a new one fast
Your cert expired, so HTTPS is broken on the origin. Users get NET::ERR_CERT_DATE_INVALID with no “proceed anyway” link, because preload sets the strict bit. There is no clickthrough for preloaded domains.
How to spot it: The cert is expired AND querying the domain in chrome://net-internals/#hsts shows it as static. No bypass exists.
3. Domain ownership transferred, new owner needs HTTP
You sold or released the domain. The new owner inherits the preload entry — they cannot host plain HTTP for the apex or any subdomain until the domain is removed from the list AND browser caches age out.
How to spot it: The new owner’s deploy works on a different domain but breaks the moment they point yourdomain.com at it without HTTPS.
4. Self-signed or internal CA cert can no longer be accepted
Before preload, users could click through cert warnings for an internal staging server. After preload, no clickthrough is possible. The internal QA team is locked out of staging.
How to spot it: Internal staging at staging.yourdomain.com shows NET::ERR_CERT_AUTHORITY_INVALID with no bypass option after preload landed.
5. Captive portal / public Wi-Fi can’t intercept
Some captive portals work by intercepting plain HTTP requests and redirecting to a login page. On your preloaded domain the browser never issues an HTTP request, so the portal can’t trigger and the user can’t sign in. Connectivity feels broken even though basic Wi-Fi works.
How to spot it: Users report the site fails on hotel/airport Wi-Fi but works elsewhere; other non-preloaded sites still load. Workaround: have them open a known-HTTP page like http://neverssl.com to surface the portal first.
6. Wildcard cert mistakes amplify because there’s no fallback
Without preload, a misconfigured wildcard at least shows a cert warning that you can bypass while troubleshooting. With preload, every misconfig is a hard fail with no clickthrough, so small mistakes become outages.
How to spot it: Any cert mismatch on a preloaded domain produces a hard NET::ERR_CERT_COMMON_NAME_INVALID with no bypass.
Before you start
- Confirm the domain is actually preloaded: visit
https://hstspreload.org/?domain=yourdomain.com. Pending and shipped entries are reported differently — note which one you see. - Know which browsers your users actually run. Chrome, Firefox, and Safari each carry their own preload list with different update cadences, and Chromium derivatives (Edge, Brave, Vivaldi, Opera) inherit Chrome’s list.
- Document your current cert state: expiry, issuer, and chain.
- Decide your real goal: “roll back permanently” or “tolerate HTTPS-only and just fix the cert.” The second is almost always the answer.
Information to collect
curl -sI https://yourdomain.com | grep -i strict-transport— is the HSTS header still being sent, and does it includepreload?- The domain’s status in
chrome://net-internals/#hsts(query box at the top).static= the preload entry;dynamic= the header your server set. - The original
max-ageandincludeSubDomainsvalues from your nginx / app config. - A list of every subdomain currently in use and whether each can serve valid HTTPS.
- An estimate of how many users are blocked or inconvenienced right now.
Step-by-step fix
Honest order: short path = restore HTTPS; long path = removal from the preload list. Try the short path first.
Step 1: First check — can you just restore HTTPS?
Most “HSTS preload stuck” tickets are really an expired cert. Reissue it.
sudo certbot renew --force-renewal
sudo systemctl reload nginx
# Confirm the new validity window:
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null \
| openssl x509 -noout -dates
If a valid cert comes back, your problem is gone. You do not need to touch the preload list. Behind a CDN, “reissuing” can be as simple as enabling the provider’s free edge certificate — Cloudflare issues one within minutes once the domain is proxied.
Step 2: For internal staging needing self-signed certs, use a non-preloaded domain
The cleanest fix is to NOT use a subdomain of your preloaded domain for internal or self-signed work. Move staging to a separately registered domain such as staging.yourdomain-internal.com that is not on the preload list.
If you must keep the subdomain on the preloaded parent, install a real publicly-trusted cert. Let’s Encrypt with the DNS-01 challenge issues for internal-only hostnames too, because DNS-01 never needs inbound HTTP — only a TXT record.
Step 3: Stop advertising preload (and optionally send max-age=0)
This is the step most guides get wrong. To become eligible for removal you do not need max-age=0. Per the official hstspreload.org/removal/ requirements, you must serve a valid HSTS header that no longer contains the preload directive. Keeping HSTS otherwise active is fine.
So the minimum change is to drop preload from the header:
# Eligible for removal: valid HSTS, no preload directive.
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
If you also want browsers to forget HSTS entirely (for example you really do need HTTP on the apex), send max-age=0 instead. That clears the dynamic cache on any browser that makes a fresh HTTPS request, per RFC 6797 §6.1.1:
# Also disables HSTS for non-preloaded clients once they reconnect over HTTPS.
add_header Strict-Transport-Security "max-age=0" always;
Either way, reload nginx (sudo nginx -t && sudo systemctl reload nginx). Neither change touches the static preload entry baked into the browser binary — but serving a preload-free header is the prerequisite for Step 4.
Step 4: Submit the removal request at hstspreload.org
Visit https://hstspreload.org/removal/ and enter your domain. To be accepted, the domain must (verbatim from the form, as of June 2026):
- Be preloaded or pending preload through
hstspreload.org. - Serve HTTPS with a valid certificate.
- Send a valid HSTS header that does not contain the
preloaddirective.
If those pass, your domain is queued for removal. It then lands per browser:
- Chrome: the removal is merged into Chromium, then ships with the next stable milestone. Chrome is on a 4-week stable cadence as of June 2026 (moving to 2-week with Chrome 153 in September 2026). Google’s own estimate is that a removal takes 6-12 weeks to reach most Chrome users.
- Firefox: similar cadence; Mozilla regenerates its list from the Chromium source.
- Safari / WebKit: a separate process, often slower.
So most up-to-date users stop enforcing preload within roughly 6-12 weeks. The genuine long tail — users who rarely update their browser — can keep the old, baked-in list for many more months. Plan for both: fast for the majority, slow for stragglers.
Step 5: Help affected users right now
Users whose browser already has the preloaded entry cannot easily bypass it. Real options:
- Switch browsers: Firefox vs. Chrome carry slightly different lists, so one may not have your domain yet. (Edge, Brave, Vivaldi, and Opera all inherit Chrome’s list, so swapping among them won’t help.)
- For internal users, deploy a real publicly-trusted cert immediately. Putting the domain behind Cloudflare’s proxy gets a working edge cert in minutes.
- For developers debugging,
chrome://net-internals/#hsts→ “Delete domain security policies” removes the dynamic entry but not the static preload. Limited utility, but worth a try when you suspect a stale dynamic entry rather than the preload list.
Step 6: Permanent rollback only if truly necessary
If you must permanently roll back (selling the domain, decommissioning):
- Serve a
preload-free HSTS header (ormax-age=0) — Step 3. - Submit removal at
hstspreload.org/removal/— Step 4. - Wait for the next stable Chrome/Firefox that drops your entry (~6-12 weeks for most users).
- Accept that users on rarely-updated browsers will keep enforcing HTTPS for months, possibly years.
- Tell whoever takes over the domain about the constraint: they cannot serve HTTP on it for the long tail of installed browsers.
How to confirm it’s fixed
https://hstspreload.org/?domain=yourdomain.comreports the domain as not preloaded (after removal ships).curl -sI https://yourdomain.com | grep -i strict-transportreturns no header,max-age=0, or at least a header with nopreloadtoken.- Querying the domain in
chrome://net-internals/#hstsreturns “not found” for the static entry on an updated Chrome build. - A fresh subdomain on the apex serves plain HTTP without the browser rewriting the scheme — only true once removal has shipped AND the testing browser has updated. Test in a browser you have NOT visited the site in, to avoid a stale dynamic entry masking the result.
Long-term prevention
- Treat
hstspreload.orgsubmission as a one-way door. Don’t submit unless you can guarantee HTTPS-only for ALL current and future subdomains, backed by a tested cert-renewal pipeline. - In production, run
max-age=31536000; includeSubDomains(one year) without thepreloaddirective. You get nearly all the security benefit and stay reversible. Submit to preload only after a year of clean HTTPS uptime, if at all. - Never submit a wildcard, internal-services, or shared-tenant domain to preload. Reserve it for the public marketing apex.
- Add cert-expiry monitoring at 25+ days out, not 7. Preload makes a cert lapse a hard outage with no user bypass.
- Record the preload constraint in your DNS-as-code repo so a future engineer doesn’t point a non-HTTPS service at a subdomain.
Common pitfalls
- Deleting the HSTS header from nginx and assuming you’re done. Preload lives in browser binaries, not your server config.
- Believing the removal form needs
max-age=0. It only requires a valid HSTS header without thepreloaddirective;max-age=0is optional and only matters for clearing dynamic caches. - Submitting to preload “for the security score” without grasping the irreversibility. Most security teams accept a one-year
max-agefor the same compliance benefit. - Trying to bypass preload in a production browser. There is no consumer-facing bypass —
thisisunsafeonly dismisses the cert-error interstitial, not preload’s strict enforcement. - Putting a sub-product on a subdomain of a preloaded parent, then being surprised that self-signed certs are unusable.
- Assuming removal lands tomorrow. It ships with the next browser milestone, not on demand — roughly 6-12 weeks for most Chrome users.
FAQ
Q: What exactly does the removal form require — do I need max-age=0?
No. As of June 2026 the hstspreload.org/removal/ form requires only that your domain still serves a valid HSTS header over a valid certificate with the preload directive removed. You may keep a normal max-age and includeSubDomains. Send max-age=0 only if you separately want to disable HSTS for non-preloaded clients.
Q: How long until removal takes effect for real users?
Google’s own guidance is 6-12 weeks for the removal to reach most Chrome users, after it merges into Chromium and ships with a stable milestone (Chrome ships every 4 weeks as of June 2026). Firefox follows on a similar cadence; Safari is its own, slower process. A genuine long tail of rarely-updated browsers can keep the old list for many more months.
Q: Can I delete a cache entry in Chrome to bypass preload?
You can clear dynamic entries (ones your server’s header set) via chrome://net-internals/#hsts → “Delete domain security policies.” You cannot clear static preload entries — they’re compiled into the browser. Using a browser that doesn’t carry the entry yet is the only real workaround.
Q: Is there a “soft preload” using max-age?
Yes. Strict-Transport-Security: max-age=31536000; includeSubDomains (one year, no preload) gives you almost all the security benefit without the irreversibility, and most compliance frameworks accept it.
Q: My security scanner deducts points for not being preloaded. Should I submit?
If the scanner is rigid, push back: preload is a one-way door, and the operational risk outweighs the marginal gain over a long max-age. NIST and CIS guidance both recognize a long max-age as a valid HSTS posture.
Related: SSL cert delay, HTTPS not forced, SSL mixed content warning, redirects broken after domain change.
Tags: #Troubleshooting #SSL #https #hsts #Security