What Strict-Transport-Security does
Without HSTS almost every visit starts with an unencrypted request: the user types example.com, the browser requests http://example.com and follows the redirect to HTTPS. That first request is vulnerable. On public Wi-Fi someone can intercept the redirect and keep the user on an HTTP copy of the site.
The Strict-Transport-Security header tells the browser: talk to this domain over HTTPS only, for the given period. From the first successful HTTPS visit on, the browser rewrites every http:// address to https:// internally before opening a connection at all. Certificate errors on HSTS domains can no longer be clicked through either. The header is only honoured over HTTPS; over HTTP the browser ignores it.
Strict-Transport-Security: max-age=31536000; includeSubDomainsRaise max-age in steps
max-age is the time in seconds for which the browser remembers the rule, and it is refreshed on every visit. That is exactly why you should not start with a year right away: if it turns out after enabling it that a resource is only reachable over HTTP, every visitor of the last few days already has the rule locked in for a year.
- Start with max-age=300 (five minutes) and test the website including all embedded resources, forms and redirects.
- Raise it to max-age=604800 (one week) and watch for support requests for a few weeks.
- Go to max-age=31536000 (one year). That is the value browsers and the preload list expect as a minimum.
includeSubDomains: every subdomain, really every one
With includeSubDomains the rule applies to every subdomain of the domain on which the header was set. Set on example.com, it covers www., shop., intranet., webmail., dev. and every subdomain someone creates in five years. Each of them then needs a valid certificate, otherwise it is unreachable in the browser, with no way to skip the warning.
In practice this hits internal systems: the intranet at intranet.example.com that only runs over HTTP on the company network, the hosting provider's webmail at webmail.example.com with a self-signed certificate, the staging environment at dev.example.com. Only when you have inventoried all subdomains and each one has clean TLS is includeSubDomains safe. Without includeSubDomains the header applies only to the exact host that sent it.
Preload: effectively irreversible
Even with HSTS the very first visit stays unprotected, because the browser does not know the header yet. The preload list solves that: Chrome, Firefox, Safari and Edge ship a built-in list of domains for which HTTPS is enforced from the start. You submit your domain at hstspreload.org.
The requirements are strict: a valid certificate, a redirect from HTTP to HTTPS on the same host, all subdomains over HTTPS, and the header on the main domain must contain a max-age of at least one year, includeSubDomains and the preload directive. The list is baked into browser releases. A removal request takes months to reach all users, and some browser versions are never updated. Preload is therefore meant for domains that run permanently and completely on HTTPS, not for clients who might switch hosting next year.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadThe pitfalls
HSTS differs from other headers in that it lives in the user's browser, not on the server. What you have served once, you cannot take back.
- A subdomain without a certificate becomes completely unreachable after includeSubDomains, and the user cannot bypass the warning.
- You cannot "turn off" HSTS. If you remove the header, browsers keep the rule until max-age expires. The only way out is to serve max-age=0 and wait until every user has visited the site once.
- An expired certificate on an HSTS domain is a total outage, because the browser no longer offers an exception button.
- Moving to a hosting provider that serves subdomains over HTTP only fails in the browsers of existing users.
- The header must be present on every HTTPS response, including redirects and error pages, otherwise max-age is not refreshed reliably.
Setting HSTS: nginx, Apache, Caddy, Cloudflare
The header belongs in the HTTPS server block, never in the HTTP block. In nginx the keyword always matters, otherwise the header is missing on error pages. In Apache mod_headers must be enabled. Caddy enables HTTPS automatically but not HSTS; the header has to be added explicitly. In Cloudflare you find HSTS under SSL/TLS, Edge Certificates, and Cloudflare shows an explicit warning before you enable it.
# nginx (inside the server block with listen 443 ssl)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# Apache (inside VirtualHost *:443, mod_headers)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Caddy (Caddyfile)
example.com {
header Strict-Transport-Security "max-age=31536000; includeSubDomains"
}Verify the result from outside with the HTTP header checker or with curl -sI https://example.com. The header must appear in the HTTPS response, and only there.
HSTS does not replace the redirect
A common misunderstanding: with HSTS you could drop the redirect from HTTP to HTTPS. The opposite is true. The very first visit of a new user and every visit after max-age expires arrives over HTTP, and there a 301 to HTTPS must be in place, otherwise the browser never sees the header. The preload list explicitly requires this redirect as well.
So the correct sequence is: HTTP request, 301 to the same URL with https://, HTTPS response carrying the HSTS header. From then on the browser takes over and performs the redirect internally without ever touching port 80 again.
Frequently asked questions
- Can I set HSTS only on www.example.com, not on example.com?
- Yes, but then it only applies there. For the preload list and for complete protection the header must be set on the main domain, because includeSubDomains works downwards from there, not upwards from www.
- How do I get rid of HSTS if a client has to go back to HTTP?
- Serve the header with max-age=0 and keep the site reachable over HTTPS until all regular users have visited it once. With preload, additionally request removal at hstspreload.org and expect months. A return to HTTP is almost never necessary today, though.
- Does HSTS affect SEO?
- Not directly. Indirectly the browser skips the HTTP detour and the page loads marginally faster on repeat visits. What matters more is that HTTPS works cleanly at all, and that is exactly what HSTS enforces.