HSTS (HTTP Strict Transport Security) is a browser-enforced rule that tells visitors’ browsers: “Only use HTTPS for this domain for the next N seconds.” Once a browser receives your HSTS header over HTTPS, it will automatically upgrade future HTTP requests to HTTPS and won’t allow click-through on invalid certificate warnings—which is great for security, but it’s exactly why misconfigurations can lock you out. (OWASP Cheat Sheet Series)
Prerequisites
Before enabling HSTS, your site must already load correctly over HTTPS with a valid certificate, and HTTP → HTTPS redirects should already be working. (HostBible hosting plans include HTTPS/SSL; make sure it’s active for your domain first.) (hostbible.com)
What HSTS does (and why it can lock you out)
When a browser receives:
Strict-Transport-Security: max-age=...
…it caches the policy for max-age seconds and will refuse to use HTTP for that hostname during that time. If HTTPS breaks (expired cert, hostname mismatch, removed SSL, wrong redirect), affected users can’t “bypass” the warning while HSTS is active. (OWASP Cheat Sheet Series)
Key directives you’ll choose from:
max-age=SECONDS— how long browsers remember the rule. (MDN Web Docs)includeSubDomains— applies HSTS to all subdomains too (powerful, higher risk). (MDN Web Docs)preload— requests inclusion in browser preload lists (treat as a long-term commitment). (MDN Web Docs)
Test-first rollout (recommended)
This guide is intentionally test-focused. You’ll test before enabling HSTS, enable with a tiny max‑age, then test again, then increase max‑age in stages.
Step 1 — Test your current HTTPS + redirects (before HSTS)
Replace example.com with your real domain.
1A) Confirm HTTPS works (no errors)
macOS / Linux
curl -I https://example.com curl -I https://www.example.com
Windows (PowerShell)
curl.exe -I https://example.com curl.exe -I https://www.example.com
Good result looks like:
Status is
200,301, or302(depending on your setup)No TLS/certificate errors
Bad result looks like:
curl: (60) SSL certificate problem: ...curl: (51) SSL: no alternative certificate subject name matches ...Timeouts / connection failures
If you see “bad” results here, stop and fix HTTPS before proceeding.
1B) Confirm HTTP → HTTPS redirects behave correctly
curl -I http://example.com curl -IL http://example.com
Good result looks like:
First response is a redirect (
301or308) tohttps://...Final response (with
-L) is the working HTTPS page
Bad result looks like:
http://returns200 OK(no redirect)Redirect loops (repeating
Location:back and forth)Redirects to the wrong hostname (e.g., to a subdomain that doesn’t have SSL)
Step 2 — Enable HSTS on HostBible (start tiny)
On HostBible’s cPanel-based hosting, the safest “quick rollback” method is to add the header at the site level (so you can change it fast if needed). HostBible support commonly covers cPanel-related hosting tasks. (hostbible.com)
Option A (recommended for most sites): add HSTS in your site’s .htaccess
Log in to your HostBible Client Area and open cPanel. (hostbible.com)
Open File Manager
Go to your site’s document root (often
public_html/or the folder for your domain)Edit (or create) the
.htaccessfileAdd this block near the top:
<IfModule mod_headers.c> # HSTS: start with 5 minutes to reduce lockout risk during testing Header always set Strict-Transport-Security "max-age=300" env=HTTPS </IfModule>
Why this is “safer”: if anything goes wrong, the worst-case browser lock is ~5 minutes for users who already received the header.
If you get a 500 error after saving, remove the new lines and try without always:
Header set Strict-Transport-Security "max-age=300" env=HTTPS
Then re-test.
Option B (VPS/Dedicated): set HSTS at the web server config level
If you manage your own server configuration, you can set the header at the vhost/server block level instead. (The testing and rollout plan below stays the same.)
Step 3 — Verify the HSTS header is present (immediately after enabling)
3A) Check that HTTPS responses include the header
curl -sI https://example.com | grep -i strict-transport-security
Good result looks like:
Strict-Transport-Security: max-age=300
Bad result looks like:
No output at all (header missing)
Multiple lines (duplicate headers)
To check duplicates:
curl -sI https://example.com | grep -i strict-transport-security | wc -l
Good: 1
Bad: 2 or more → remove duplicates (pick one place to set it: server OR app OR .htaccess).
3B) Confirm the header appears on the final HTTPS response after redirects
curl -IL http://example.com | grep -i strict-transport-security
Good: you see the header at least once on the HTTPS response in the chain.
Note: Browsers only honor HSTS delivered over HTTPS; you can’t “turn it on” or “turn it off” via plain HTTP. (MDN Web Docs)
Safe rollout plan (max‑age stages)
Once max-age=300 is verified, increase in stages. A practical schedule:
Stage 1 — 5 minutes (already done)
Strict-Transport-Security: max-age=300
Stage 2 — 1 day
Strict-Transport-Security: max-age=86400
Stage 3 — 1 week
Strict-Transport-Security: max-age=604800
Stage 4 — 1 month
Strict-Transport-Security: max-age=2592000
Stage 5 — 6–12 months (common long-term setting)
Strict-Transport-Security: max-age=31536000
Rule: don’t move to the next stage until you can run all tests again and everything looks “good”.
includeSubDomains: only enable if every subdomain is HTTPS-ready
includeSubDomains is a security win, but it increases lockout risk because one broken subdomain becomes a problem for users once their browser has cached the policy. (OWASP Cheat Sheet Series)
includeSubDomains readiness checklist
Before adding it, confirm:
Every subdomain you use has a valid certificate and works over HTTPS
Every subdomain redirects HTTP → HTTPS (or at least serves HTTPS cleanly)
You’ve considered “hidden” or internal subdomains that still exist in DNS
If you’re aiming for preload later, note that preload applies to all subdomains, including internal ones. (hstspreload.org)
Test your subdomains (copy/paste pattern)
Create a list of subdomains you actually use (examples: www, blog, shop, app, api, etc.) and test each:
for host in www.example.com blog.example.com api.example.com; do echo "== $host ==" curl -I "https://$host" | head -n 5 done
Bad result examples:
certificate errors (curl exits with
(60)or(51))timeouts
redirects to HTTP
Enable includeSubDomains (only after it’s clean)
Start with a moderate max-age first:
Header always set Strict-Transport-Security "max-age=604800; includeSubDomains" env=HTTPS
Then re-run:
curl -I https://example.com | grep -i strict-transport-securitysubdomain tests (above)
preload: treat as “hard to undo”
preload is used to request inclusion in browser HSTS preload lists. It’s powerful because it protects even first-time visitors—but it’s also the hardest to roll back. (Chrome for Developers)
Preload requirements (must meet all)
To be eligible, your site must serve an HSTS header on the base domain where:
max-ageis at least 31536000 (1 year)includeSubDomainsis presentpreloadis present (hstspreload.org)
Also, if www exists in DNS, it must support HTTPS as well. (hstspreload.org)
Preload header value
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS
Recommendation: don’t add preload until you’ve run with includeSubDomains safely for a while and you’re confident all current and future subdomains will remain HTTPS-only.
Lockout prevention and recovery plan (bookmark this)
This is the part that saves the most time if something goes wrong.
Lockout prevention checklist
Do these before increasing max‑age beyond a short test window:
Start with max-age=300, verify, then increase gradually (don’t jump to 1 year on day one).
Inventory subdomains (current + likely future). If you can’t guarantee them, delay
includeSubDomains.Make sure you can still access your hosting controls without relying on the website (HostBible Client Area, cPanel access, File Manager, etc.). (hostbible.com)
Keep a “break glass” path:
Know exactly where your
.htaccessisKeep a copy of the last working version
Make sure another team member has access too
Recovery: “I enabled HSTS and now I’m locked out”
First, understand what’s happening:
HSTS means the browser refuses HTTP and may refuse to bypass certificate warnings. (OWASP Cheat Sheet Series)
So the fix is almost always: restore working HTTPS, then adjust HSTS safely.
Scenario A — HTTPS certificate is broken / expired / wrong hostname
Fix: restore valid HTTPS for the affected hostname(s).
Use HostBible control access (Client Area/cPanel/File Manager) to fix config and renew/restore SSL. (hostbible.com)
Once HTTPS works again, decide whether to keep HSTS or reduce it.
Scenario B — You need to disable HSTS (rollback)
To disable, you must send a new header over HTTPS with max-age=0 (you cannot disable HSTS over HTTP). (MDN Web Docs)
Set:
<IfModule mod_headers.c> Header always set Strict-Transport-Security "max-age=0" env=HTTPS </IfModule>
Then verify:
curl -sI https://example.com | grep -i strict-transport-security
Important: If you simply remove the header, browsers that already cached it will continue enforcing it until the original expiry time. Setting max-age=0 is the explicit “turn off” signal. (MDN Web Docs)
Scenario C — You enabled includeSubDomains but one subdomain isn’t ready
Fix order:
Restore HTTPS on that subdomain (preferred).
If you must unwind quickly, temporarily set
max-age=0on the base domain (and on any subdomain that also sends its own HSTS header). Then rebuild with a safer staged plan.
Scenario D — You used preload and now want to undo it
Expect this to take longer than normal rollback. Preload is intended as a long-term commitment and can have “hard to undo” consequences. (OWASP Cheat Sheet Series)
If you’re not 100% sure, don’t enable preload yet.
Quick “good vs bad” reference (copy/paste)
✅ Good (safe test stage)
Strict-Transport-Security: max-age=300
✅ Good (long-term, no subdomains)
Strict-Transport-Security: max-age=31536000
✅ Good (all subdomains HTTPS-ready)
Strict-Transport-Security: max-age=31536000; includeSubDomains
⚠️ Risky (only do if you truly want preload)
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
❌ Bad (header missing on HTTPS)
No Strict-Transport-Security header on https://... responses.
❌ Bad (subdomain not HTTPS-ready + includeSubDomains enabled)
Any subdomain fails TLS or redirects incorrectly.
