What's Happening
You open a site in your browser and hit a wall:
You cannot visit this site right now because it uses HSTS.
Network errors and attacks are usually temporary, so this page will probably work later.
The browser isn't broken. It's doing exactly what it was told. HSTS (HTTP Strict Transport Security) is a security policy that orders browsers: never connect to this domain over plain HTTP, only HTTPS. Once that instruction is in place โ from a previous visit or from the HSTS preload list built into the browser itself โ it enforces HTTPS absolutely. Any HTTP request gets killed before it leaves your machine.
This error shows up in two situations:
- You're a developer who enabled HSTS, then broke HTTPS โ expired cert, misconfigured redirect, or local dev running without TLS.
- You're visiting a domain that either sent a valid HSTS header during a previous session, or is listed in the browser's hardcoded preload list.
Root Cause
HSTS enforcement comes from two completely separate places:
- Browser HSTS cache: When your browser visits a site sending
Strict-Transport-Securityheaders, it stores that policy locally. Every future visit automatically upgrades HTTP to HTTPS. If HTTPS fails, the browser shows this error โ it won't fall back to plain HTTP. - Preload list: Chrome, Firefox, Edge, and Safari all ship with a hardcoded list of domains locked to HTTPS. If your domain is on it, even a brand-new browser install blocks HTTP. The list is compiled into the browser binary. Clearing your cache does nothing.
Diagnosing Which Case You're In
Check Chrome's HSTS cache
Open Chrome and go to:
chrome://net-internals/#hsts
Under Query HSTS/PKP domain, type your domain (e.g., example.com) and click Query. A result means Chrome has HSTS cached for that domain.
Look at the static_sts_domain field in the output. If it reads true, the domain is on the preload list. Cache clearing won't help โ you're in Fix 3 territory.
Check Firefox's HSTS status
Firefox has no internal page equivalent to Chrome's. The fastest route is hstspreload.org โ paste your domain and it tells you immediately whether it's preloaded and in which browsers.
For locally cached HSTS (not preload), clearing Firefox's site preferences removes it. See Fix 1 below.
Fix 1: Clear the Browser HSTS Cache (For Users)
This works only if the domain is not on the preload list. If it is, skip straight to Fix 3.
Chrome
- Go to
chrome://net-internals/#hsts - Scroll to Delete domain security policies
- Enter the domain (e.g.,
example.com) โ nohttp://orhttps:// - Click Delete
- Run Query again to confirm โ it should return nothing
Firefox
- Close all tabs for the affected site
- Open the History menu โ Clear Recent History
- Set time range to Everything
- Check Active Logins and Site Preferences
- Click Clear Now
Site Preferences is what holds HSTS data. Clearing only "Cache" won't touch HSTS records โ a common mistake.
Edge
edge://net-internals/#hsts
Same flow as Chrome. Find Delete domain security policies, enter the domain, delete.
Safari (macOS)
Safari provides no UI for this. You have to delete the file directly:
- Quit Safari completely
- Delete the HSTS database:
rm ~/Library/Cookies/HSTS.plist
- Reopen Safari
Fix 2: Fix the Server-Side HSTS Configuration (For Developers)
If you enabled HSTS and now need HTTP access โ local dev, domain migration, an expired cert โ here's how to unwind it without locking out your own users.
Lower the max-age before removing HSTS
Don't just delete the HSTS header cold. Browsers cache the old policy until max-age expires, so existing visitors stay blocked regardless. Set max-age=0 first so new visitors stop enforcing HSTS as the old caches drain:
# Nginx
add_header Strict-Transport-Security "max-age=0" always;
# Apache
Header always set Strict-Transport-Security "max-age=0"
Wait out the original max-age window โ up to 365 days if you set max-age=31536000. Then remove the header entirely.
If your SSL cert expired or HTTPS is broken
Fix HTTPS first. Nothing else matters until that's working. Renew the cert:
# Let's Encrypt / Certbot
sudo certbot renew
sudo systemctl reload nginx
# Verify the cert is valid
curl -I https://yourdomain.com
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com 2>/dev/null | openssl x509 -noout -dates
Local development without HTTPS
Use a different hostname for local dev โ don't run the production domain locally. Something like myapp.local sidesteps HSTS entirely. If you actually need HTTPS locally, mkcert generates browser-trusted local certs in under a minute:
mkcert -install
mkcert localhost 127.0.0.1 myapp.local
Fix 3: Remove from HSTS Preload List (Long Process)
Browser cache cleared and still blocked? The domain is on the preload list. Cache clearing is irrelevant here. There's only one exit:
- Keep HTTPS working. The preload list maintainers won't process a removal request if your HTTPS is broken.
- Remove the
preloaddirective from your HSTS header:
# Before (has preload)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# After (remove preload directive)
Strict-Transport-Security: max-age=31536000; includeSubDomains
- Submit a removal request at hstspreload.org/removal
- Wait โ removal takes months. It requires a Chrome update to actually reach users.
Users on older browser versions stay blocked the entire time. This is permanent-level commitment. Never add preload to a domain you might ever need to walk back to HTTP.
Verification
After applying the fix, run these checks:
# Check current HSTS headers from your server
curl -sI https://yourdomain.com | grep -i strict
# Confirm HTTP redirects properly
curl -sI http://yourdomain.com | grep -i location
# Test the full TLS chain
openssl s_client -connect yourdomain.com:443 -servername yourdomain.com
Back in Chrome, go to chrome://net-internals/#hsts and query your domain. A successful cache clear returns nothing. If static_sts_domain: true still appears, the domain is preloaded โ the browser cache was never the issue.
Prevention
HSTS is a one-way door. Treat it that way before flipping the switch โ especially with preload.
- Set up SSL cert auto-renewal before enabling HSTS. Certbot's systemd timer handles Let's Encrypt automatically; AWS ACM renews on its own. A dead cert plus HSTS locks users out with no quick escape.
- Test with a short
max-agefirst โmax-age=300gives you a 5-minute window to catch problems before committing to a year. - Never add
preloadto a domain you might ever need to revert to HTTP. The exit process alone takes months. - Monitor cert expiry actively. By the time users report the HSTS error, the cert has already been dead long enough for the damage to spread.
When chasing SSL or HTTPS issues that involve firewall rules and routing, CIDR ranges tend to come up. ToolCraft's Subnet Calculator handles that quickly โ runs entirely in the browser, no data sent anywhere.
Lessons Learned
- HSTS is intentionally hard to undo. Browsers trust the cached policy over whatever the server says right now โ that's the whole point of the security model.
- The preload list is not the browser cache. These are different mechanisms with different fixes. Clearing cache does not remove preload entries.
- Start with
max-age=300when testing HSTS. Only bump to 1 year โ and addpreloadโ when you're fully committed and HTTPS is solid. - Inheriting a domain with HSTS problems? Check hstspreload.org immediately. It tells you upfront whether the fix takes hours or months.

