Redirecting HTTP to HTTPS isn't enough on its own. The first request still goes out unencrypted, and someone on the same café Wi-Fi can intercept it before your redirect arrives. HTTP Strict Transport Security (HSTS) closes most of that gap by telling browsers to skip HTTP entirely for your domain. It's a single header, but includeSubDomains and preload can lock real users out if you rush them. This guide explains each directive and gives you a rollout plan that avoids that.
Key takeaways
- HSTS tells browsers to skip HTTP for your domain, but keep your HTTP-to-HTTPS redirect for first-time visitors.
- Ramp max-age in stages from 5 minutes to 1 week to 30 days before moving to a long-term value.
- Only add includeSubDomains once every subdomain serves a valid certificate, or browsers will refuse to load those hosts.
- The preload list cannot easily be undone, so a standard one-year header without preload is safer for complex setups.
What HSTS actually does
When a browser receives this header over a valid HTTPS connection:
Strict-Transport-Security: max-age=31536000; includeSubDomains
it records your host as HTTPS-only for the next 31,536,000 seconds (one year). From then on:
- Any
http://link, bookmark or typed URL for your domain is rewritten tohttps://inside the browser, before a request leaves the device. - If the certificate is invalid (expired, wrong name, untrusted), the user cannot click through the warning. The page simply won't load.
- Every response that carries the header resets the timer to "now plus max-age".
Browsers ignore the header when it arrives over plain HTTP. That's deliberate: otherwise an attacker on the network could inject a fake policy or strip yours.
The three directives
max-age (required)
The number of seconds the browser remembers the policy. Common values:
| Value | Duration | Use |
|---|---|---|
300 |
5 minutes | First test |
604800 |
1 week | Ramp-up |
2592000 |
30 days | Ramp-up |
31536000 |
1 year | Standard production, minimum for preload |
63072000 |
2 years | OWASP's suggested value once you're confident |
max-age=0 tells browsers to forget the policy, but only browsers that visit over HTTPS and receive it. It's an off switch, not an undo button. Anyone who doesn't return keeps the old policy until it expires.
includeSubDomains (optional)
This applies the policy to every subdomain of the host that sent it: www, shop, mail, staging, printer.office, all of them. This is where most HSTS incidents come from. If any subdomain only works over HTTP, or uses a self-signed certificate, browsers that saw the header on your apex domain will refuse to load it.
Typical casualties:
- Internal tools on
intranet.example.comwith a self-signed certificate. - Router, NAS or printer admin pages under your domain.
- A legacy marketing microsite on a host with no certificate.
- Third-party services you've pointed a CNAME at (help desks, landing page builders) that don't serve your certificate.
Before adding includeSubDomains, list every DNS record under your domain and check that each hostname serves a valid certificate. Your DNS zone and certificate transparency logs (search your domain on crt.sh) are good places to find forgotten hosts. Our guide to DNS records explains what to look for.
preload (optional)
preload signals that you want your domain hardcoded into browsers' built-in HSTS lists. On its own the directive does nothing. You also have to submit the domain at hstspreload.org, which feeds Chrome's list. Other major browsers maintain preload lists of their own that are based on Chrome's. Once your domain ships in a browser release, even a first-ever visit goes straight to HTTPS.
The first-visit problem
Plain HSTS has one weak spot: it only works after the browser has seen the header once. A brand-new visitor, or someone whose policy expired, still makes one HTTP request. MDN's recommended setup:
- The HTTP site answers with a
301redirect to the HTTPS URL on the same host. Don't send the HSTS header on this redirect. Browsers ignore it there. - The HTTPS response carries the HSTS header.
- Preloading, if you choose it, covers that very first visit.
Preload requirements (current)
To be accepted at hstspreload.org, your site must:
- Serve a valid certificate.
- Redirect HTTP to HTTPS on the same host, if it listens on port 80.
- Serve all subdomains over HTTPS, including
wwwif a DNS record exists for it, and including internal-only subdomains. - Send this on the base domain over HTTPS:
max-ageof at least31536000includeSubDomainspreload- If the HTTPS base domain redirects (for example to
www), the redirect must also carry the header.
You must keep meeting these requirements. Removing the preload token makes you eligible for removal, and the site warns that domains may be removed automatically in future if they stop complying.
The risks of preloading
The preload list is the right choice for some sites and a trap for others. Before you submit, know this:
- It's slow to undo. Inclusion "cannot easily be undone", according to hstspreload.org. Removal requests take months to reach users through browser updates, and there's no guarantee about timing in non-Chrome browsers.
- It applies to every subdomain, forever-ish. A future project that needs plain HTTP on a subdomain, such as a device that can't do TLS or a vendor that won't support your certificate, won't work.
- Certificate mistakes become outages. An expired certificate on any preloaded host means a hard block with no click-through for every visitor. With certificate lifetimes getting shorter (see our post on certificate lifetime changes), automated renewal and expiry monitoring are mandatory.
- Leaving your CDN gets riskier. Cloudflare's docs warn specifically against pausing Cloudflare, switching records to DNS-only, or moving nameservers while HSTS is active unless the origin serves valid HTTPS itself.
Some top-level domains, such as .dev and .app, are preloaded as a whole TLD. Every site on them is HTTPS-only regardless of headers.
A safe rollout plan
hstspreload.org recommends ramping max-age in stages and waiting out each stage before moving on:
# Stage 1 - 5 minutes
Strict-Transport-Security: max-age=300; includeSubDomains
# Stage 2 - 1 week
Strict-Transport-Security: max-age=604800; includeSubDomains
# Stage 3 - 1 month
Strict-Transport-Security: max-age=2592000; includeSubDomains
# Stage 4 - long term (add preload only if you intend to submit)
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
If you aren't sure about subdomains yet, run stages 1 to 3 without includeSubDomains on the apex, then add it once your inventory is clean.
Nginx
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# ... certificates and site config
}
Apache
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# ... SSL config
</VirtualHost>
Cloudflare
Go to SSL/TLS > Edge Certificates > HTTP Strict Transport Security (HSTS), enable it, and choose max age, includeSubDomains and preload. Cloudflare only adds the header to HTTPS responses. To disable it, set Max Age to 0 and leave it in place until returning visitors have picked it up.
How to check what browsers have stored
In Chrome, open chrome://net-internals/#hsts, enter your domain under "Query HSTS/PKP domain", and you'll see whether it's dynamically stored (from your header) or static (preloaded). You can also delete a dynamic entry there while testing. From a terminal:
curl -sI https://example.com | grep -i strict-transport-security
Frequently asked questions
Does HSTS replace my HTTP-to-HTTPS redirect?
No, keep both. The redirect handles first-time visitors and clients that don't support HSTS. HSTS then makes returning visitors skip the HTTP step entirely.
Should every site use includeSubDomains?
Only once you've confirmed every subdomain serves valid HTTPS. It's also needed for preload and protects against cookie-injection tricks through insecure subdomains. If you can't vouch for all subdomains, leave it off for now and fix the stragglers first.
I set max-age to two years by mistake and a subdomain broke. What now?
Get a valid certificate onto the broken subdomain. That's the only fix that works for everyone. Serving max-age=0 from the apex helps visitors who come back, but those who don't stay locked to HTTPS until their stored policy expires.
Is preload worth it for a small business site?
It adds protection for first visits, which matters most for banks, healthcare and sites handling logins on public networks. For a brochure site with a handful of subdomains you fully control, it's reasonable. If you have an IT department, legacy devices or many vendors on subdomains, a standard one-year HSTS header without preload is the safer choice.
What to do next
Inventory your subdomains, start HSTS at five minutes, and ramp up over about six weeks. Pair it with automated certificate renewal so a renewal failure can't lock visitors out. Run a free audit to confirm the header is present, check its max-age, and see your certificate's expiry date in one place. If you want scheduled re-checks with email alerts, those are on our paid plans.
Related reading
- TLS 1.0 and 1.1: How to Check Your Server and Disable Them: Check which TLS versions your server accepts, find out who still uses old ones, then disable TLS 1.0 and 1.1 on Apache, Nginx, IIS, cPanel and Cloudflare.
Sources
Written by the MakeItFlow team
We build the website audit these guides are based on. Every fact is checked against the primary sources listed above . How we research and check
Check your own site in 30 seconds
Run a free audit covering speed, SEO, DNS, email authentication and security headers — and get a prioritised fix list.