Skip to content
  • FG-30
  • 12 min read
  • Last checked November 7, 2026

How to Fix “You Cannot Visit This Site Right Now Because the Website Uses HSTS”

HSTS removes the “proceed anyway” link, so any certificate fault locks visitors out. Learn how the header works, how to clear it for testing, and how to roll it out safely.

Run the health check

Chrome shows “Your connection is not private”, but this time with an extra line: “You cannot visit example.com right now because the website uses HSTS. Network errors and attacks are usually temporary, so this page will probably work later.” The usual Advanced, “Proceed to example.com (unsafe)” link is missing. Firefox shows a similar page that says the site uses HTTP Strict Transport Security and offers no exception button. You, your team and your visitors are locked out.

HSTS (HTTP Strict Transport Security) is a promise your site made to browsers earlier: “only ever talk to me over valid HTTPS”. The browser is now keeping that promise. Something is wrong with the certificate or the HTTPS connection, and because of HSTS the browser refuses to let anyone click past it. Site owners usually hit this when a certificate expires, after a migration to a server with the wrong certificate, or when a subdomain that never had HTTPS gets caught by a policy set on the main domain.

What is happening

When your site sends this response header over a valid HTTPS connection, the browser stores a policy for the hostname:

Strict-Transport-Security: max-age=63072000; includeSubDomains; preload

This is an example header, not a command. Each part has a job:

Directive What it does
max-age How long, in seconds, the browser remembers the policy. 63072000 is two years. The timer restarts every time the browser sees the header again. max-age=0 tells the browser to forget the policy.
includeSubDomains Applies the policy to every subdomain at any depth, including ones that have never had HTTPS.
preload Signals consent to be added to the HSTS preload list built into browsers. On its own it does nothing; the domain must be submitted.

Once a browser holds the policy, two things change. First, it rewrites any http:// address for that host to https:// before sending anything. In Chrome devtools this shows as a 307 Internal Redirect that never touched your server. Second, any certificate error becomes fatal. The HSTS standard (RFC 6797) tells browsers not to give users a way to bypass certificate errors on HSTS hosts, because the whole point is to stop an attacker presenting a fake certificate and relying on people clicking through.

Browsers only accept the header over HTTPS with a certificate that validated without errors. A header sent over plain HTTP is ignored. That is why you can never get HSTS “by accident” from an HTTP page, and also why you cannot remove it by sending something over HTTP.

The preload list is different. It is a list compiled into Chrome and shared with other major browsers, including Firefox, Safari and Edge. A preloaded domain is treated as HSTS from the very first visit, on every fresh install, and visitors cannot clear it. Whole top-level domains are preloaded too: every .dev and .app domain, for example, requires HTTPS in browsers, which surprises developers using those for local testing.

Before you start

You need access to your hosting panel or server config, your CDN dashboard if you use one, and DNS. No database backup is needed for header changes, but copy any config file before you edit it.

How to run the commands in this guide. Checks run on your own computer in Terminal (macOS or Linux) or WSL on Windows; curl.exe in PowerShell also works for the curl checks. Server changes are files you edit on the server over SSH or in a panel file manager. If HSTS is set by a WordPress plugin, you may also use wp-cli from the site folder, the folder containing wp-config.php; the command is wp or wp-cli depending on your host. Browser steps happen at special internal pages typed into the address bar.

Step 1: Fix the certificate problem underneath

HSTS is never the root cause. It only removes the bypass. The real fault is one of the certificate or connection errors that would normally show a click-through warning. Read the error code on the warning page, or click it to expand the details:

  • NET::ERR_CERT_DATE_INVALID: the certificate expired or the device clock is wrong. See our ERR_CERT_DATE_INVALID guide.
  • NET::ERR_CERT_COMMON_NAME_INVALID: the certificate does not list this hostname. See our name mismatch guide.
  • NET::ERR_CERT_AUTHORITY_INVALID: self-signed certificate, incomplete chain or interception. See our authority guide.
  • ERR_SSL_PROTOCOL_ERROR and similar: the handshake fails. See our handshake guide.

Confirm what the server presents from your computer:

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -dates -ext subjectAltName

Replace example.com in both places with the locked-out hostname. -servername sends the hostname as SNI so the server picks the right certificate. The second command prints the subject, the validity dates and the list of names covered. Good output shows a notAfter date in the future and your hostname in the SAN list. Bad output shows a past date, a missing name or no certificate at all. Fix that, and the HSTS warning disappears with it, because the browser was only enforcing HTTPS that now works.

Step 2: Read the HSTS header your site sends

Next, learn exactly what policy you are dealing with. Once HTTPS works again (or on a hostname that still works), run on your computer:

curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI https://www.example.com/ | grep -i strict-transport-security

-s hides progress output, -I fetches headers only, and grep -i finds the header regardless of case. Replace example.com with your domain and test every hostname you serve. Good output is a single header line whose directives match your intent. Watch for these warning signs:

  • Two headers. Both a plugin and the server (or CDN) add one. Browsers process only the first, which may not be the one you think. Remove one source.
  • includeSubDomains you did not plan for. Every subdomain is now HTTPS-only for visitors who saw it.
  • A long max-age on a site still being set up. Mistakes now last for as long as that number says.

Then find where the header comes from. Common sources are the web server config, an .htaccess file, a security or SSL plugin, and the CDN. In Cloudflare, look in SSL/TLS, Edge Certificates, HTTP Strict Transport Security (HSTS). On the server, search for it:

grep -rni "strict-transport-security" /etc/nginx /etc/apache2 /etc/httpd 2>/dev/null
grep -ni "strict-transport-security" .htaccess

Run these on the server; the second one from the site folder. -r searches folders recursively, -n shows line numbers, -i ignores case, and 2>/dev/null hides errors for folders that do not exist on your system. Each match shows the file and line that sets the header. No output from either means the header comes from a plugin or the CDN.

Step 3: Clear the HSTS entry in your own browser for testing

While you work, your own browser may keep forcing HTTPS on a hostname you are deliberately testing over HTTP, such as a subdomain you are moving. You can clear the stored policy for your browser only. This does nothing for visitors and cannot remove a preloaded entry.

Chrome, Edge and other Chromium browsers

  1. Type chrome://net-internals/#hsts in the address bar (in Edge, edge://net-internals/#hsts).
  2. Under Query HSTS/PKP domain, enter the hostname and click Query. A result with dynamic_sts_domain means your browser learned it from the header; static_sts_domain means it is preloaded.
  3. Under Delete domain security policies, enter the exact hostname and click Delete. Repeat for the parent domain if the policy came from there with includeSubDomains.
  4. Query again. “Not found” means the dynamic entry is gone.

Delete only removes dynamic entries. A static, preloaded entry stays, and you cannot override it in a normal browser.

Firefox

Open the History menu, choose Manage History (the Library window), find the site, right-click it and choose Forget About This Site. This removes the HSTS state for that domain, but it also deletes its history, cookies, cache, saved passwords and permissions, so be sure before you click. Do not rely on a private window as a workaround: preloaded entries apply there too.

Testing without clearing anything

curl does not keep an HSTS cache unless you ask it to with the --hsts option, so it is a clean way to see what the server really does over HTTP: curl -sI http://sub.example.com/, replacing sub.example.com with the hostname. That shows the server’s own response without any browser memory involved.

Step 4: Fix subdomains broken by includeSubDomains

This is the classic self-inflicted lockout. The main site sends includeSubDomains, and a subdomain that only works over HTTP becomes unreachable for anyone whose browser has visited the main site. Typical victims are an old staging site, a webmail or control panel address, a printer or NAS on an internal name, an intranet, and email marketing click-tracking domains set up as a CNAME to a provider that does not offer HTTPS on custom domains.

Confirm it

The subdomain fails in your browser with a connection or certificate error, while curl -sI http://sub.example.com/ on your computer returns a normal HTTP response. In Chrome devtools, the Network tab shows a 307 Internal Redirect to HTTPS for the request. And the header on the parent domain, from Step 2, includes includeSubDomains.

Fix it

The right fix is to give the subdomain working HTTPS: a certificate that covers it (a separate certificate or a wildcard), a 443 virtual host, or, for a third-party service, the provider’s HTTPS option for custom domains. That is permanent and works for everyone.

If you cannot add HTTPS soon, stop the damage spreading by removing includeSubDomains from the parent domain’s header. Browsers that already stored the policy keep it until it expires, unless they revisit the parent over HTTPS and see a new header. A browser that sees a fresh header without includeSubDomains updates its stored policy for the parent host, so over time, as visitors return, the subdomain recovers. If the domain is preloaded with includeSubDomains, removing the directive does not help until the preload entry itself is removed (see Step 5), which is why HTTPS on the subdomain is usually the only realistic path.

Step 5: Understand preload list realities

Check your domain’s status at hstspreload.org. If it says the domain is preloaded or pending, every browser that ships the list will force HTTPS on it and every subdomain, from the first visit, with no way for users to clear it.

Removal is possible but slow. Per hstspreload.org, you first remove the preload directive from your header, which makes the domain eligible for the removal form. The change then has to reach the browser source code and ship in new browser releases, and visitors have to update. hstspreload.org says a removal may take 6 to 12 weeks to reach most Chrome users and longer for other browsers, and older browser builds that never update keep the entry. Plan as if preloading is permanent.

Preloading also has strict entry rules. hstspreload.org requires a valid certificate, a redirect from HTTP to HTTPS on the same host, HTTPS on all subdomains (including www if it has a DNS record), and a header on the base domain with a max-age of at least 31536000 seconds (one year), plus includeSubDomains and preload. Some security plugins and CDN panels add preload with one click; adding the directive is consent to be listed, so do not check that box casually.

Step 6: Roll HSTS out safely, or roll it back

HSTS is worth having, because it closes the window where a first HTTP request could be intercepted. The safe approach ramps up slowly so a mistake costs minutes, not years. hstspreload.org recommends stepping through short values first. A sensible plan:

  1. Confirm every hostname you serve has a valid certificate and redirects HTTP to HTTPS. Set up certificate expiry monitoring for each.
  2. Send max-age=300 (five minutes) on the main hostname, without includeSubDomains. Watch for a few days.
  3. Raise to max-age=604800 (one week), then max-age=2592000 (one month), checking errors at each step.
  4. Inventory every subdomain from DNS, including internal ones and third-party CNAMEs. Only when all of them serve HTTPS, add includeSubDomains, starting again with a short max-age.
  5. Move to max-age=63072000 (two years). Add preload and submit only if you are sure about the future of every subdomain.

For Nginx, inside the HTTPS server block (a file you edit on the server):

add_header Strict-Transport-Security "max-age=MAX_AGE_SECONDS" always;

For Apache with mod_headers, in the HTTPS virtual host or .htaccess:

Header always set Strict-Transport-Security "max-age=MAX_AGE_SECONDS"

MAX_AGE_SECONDS is the current step of your ramp, such as 300. Add ; includeSubDomains inside the quotes only at the right stage. always sends the header on error responses too. One Nginx trap: if a location block contains any add_header line of its own, it stops inheriting the server-level add_header lines, so pages served from that location lose the header. Check several URLs with curl after a change, and reload with sudo nginx -t then sudo systemctl reload nginx.

To roll back, do not just delete the header. Browsers keep the old policy until it expires. Instead, send max-age=0 over valid HTTPS for at least as long as your old max-age, or until you are satisfied most returning visitors have seen it. Each browser that receives it drops the policy. Then remove the header. In Cloudflare’s HSTS settings, the same principle applies: lower the max-age to zero before disabling the feature.

Advanced: Watching HSTS in action

To see exactly when HSTS rather than your server is redirecting, open Chrome devtools, Network tab, check Preserve log, and load http://example.com/. The first entry shows status 307 Internal Redirect with a response header Non-Authoritative-Reason: HSTS. That request never left the browser. If you see a 301 from your server instead, the browser has no HSTS entry and your server redirect did the work.

The parent domain matters for includeSubDomains. A browser only learns a policy for example.com if it actually loads something from https://example.com. If your site lives on www.example.com and the bare domain only redirects, visitors who type the www address directly never receive the apex policy. Some sites deliberately load one small resource from the apex for that reason. The flip side is that any visitor who did hit the apex with includeSubDomains now enforces HTTPS on every subdomain, which explains why a subdomain breaks for some people and not others.

Finally, a lockout can appear that has nothing to do with your server. Corporate networks that intercept HTTPS with their own certificate authority, captive Wi-Fi portals, and wrong device clocks all trigger certificate errors that HSTS makes unclickable. Test from another network and device before changing anything.

When to contact your host

Open a ticket if you cannot find where the header is set, if the certificate on the server is not the one you expect, or if you need TLS configured on a subdomain. Send:

  • The exact warning text and the error code shown on the page.
  • The output of the curl header check and the openssl certificate check for each affected hostname.
  • Your domain’s status from hstspreload.org.
  • Whether a CDN or security plugin also sets headers, and the UTC time you tested.
  • What changed recently, such as a certificate renewal, migration, new subdomain or plugin setting.

If the main site is locked out for everyone, our Emergency Room gives you a triage order, and the diagnostic tools page lists header and certificate checkers.

Still stuck?

Print a free one-page checklist to keep, or open the Emergency Room if the symptom does not match.

Get the free checklists

Keep reading

All field guides

Search the field manual

What is going wrong?

Press / to search from any page, Esc to close