HSTS setup: Strict-Transport-Security, max-age and the preload list
HSTS tells browsers to reach your website over HTTPS and nothing else. Adding the header takes a minute. Extend it to every subdomain too early, though, and you may lock yourself out of your own test server.
Updated: 05 November 2026
What HSTS does
When someone types example.com without a scheme, the browser first asks over plain HTTP. Only the server's redirect moves it to HTTPS. On a hostile Wi-Fi network an attacker can intercept that request, swallow the redirect and keep the visitor on an unencrypted copy of the site. This is known as SSL stripping.
HSTS (HTTP Strict Transport Security, RFC 6797) closes the gap. Your site sends the Strict-Transport-Security header over HTTPS and the browser records the host. From then on it rewrites every http:// link to that host as https:// before a single packet leaves the device. Certificate errors can no longer be clicked away either. The connection fails.
The header
Strict-Transport-Security: max-age=31536000; includeSubDomains
| Directive | Meaning |
|---|---|
max-age= |
required: how many seconds the browser keeps the HTTPS rule; every response carrying the header restarts the clock |
includeSubDomains |
the rule also covers every subdomain of the host |
preload |
consent to inclusion in the preload list; not part of RFC 6797 |
Each directive may appear once. A header with no readable max-age, or with a directive repeated, is invalid and browsers discard it. max-age=0 switches HSTS off.
ZwoWebCheck treats six months or more as long enough and recommends a year (31536000). With a month, a customer who drops by every quarter arrives unprotected each time.
Browsers only accept the header over HTTPS. Over plain HTTP anyone on the network could forge it, so it is ignored there.
The first visit and the preload list
HSTS only takes effect once the browser has loaded the site cleanly over HTTPS. A first-time visitor has no protection yet, and neither does anyone whose entry has expired. The preload list covers that case. Chrome maintains it at hstspreload.org and the other major browsers build on it, so a listed domain is known to the browser from the moment it is installed.
For a domain to be accepted, hstspreload.org requires:
- a valid certificate;
- on port 80, a redirect from HTTP to HTTPS on the same host first, so
http://example.comgoes tohttps://example.combefore any hop towww; - HTTPS on all subdomains, including
wwwif a DNS record exists for it; - the header on the base domain with a
max-ageof at least31536000, plusincludeSubDomainsandpreload; any further redirect served over HTTPS must carry it too.
Only whole domains can be submitted, and getting off the list is slow. A removal takes months to reach users through browser updates, with no promise at all for browsers other than Chrome. Apply only once every subdomain will support HTTPS for good.
Rolling it out safely
- Start short.
max-age=300is five minutes, so any mistake wears off quickly. - Raise it in steps. One week (
604800), one month (2592000), then a year. Keep each step running for at least its ownmax-age. - Add
includeSubDomainsonce every subdomain answers over HTTPS with a valid certificate. Remember the intranet, the printer's web interface and that forgotten staging host. Any browser that has seen the directive will refuse to reach a subdomain without HTTPS until the policy expires. - Preload, if you are certain: add
preloadand submit the domain at hstspreload.org.
In nginx the line belongs in the server block for port 443:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
Without always, nginx leaves the header off error pages. Inheritance is the subtler trap. Once a location block has an add_header of its own, the headers from the level above no longer apply there, and HSTS quietly disappears for those paths.
In Apache, with mod_headers, inside the port 443 VirtualHost:
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Common mistakes
- The header is missing from some responses, such as error pages. If a visitor lands on one of those first, the browser learns nothing.
- The header goes out over HTTP as well. Browsers ignore it there, and RFC 6797 forbids servers from sending it.
max-age=0left over from testing. The header is present, yet HSTS is off.- Both the reverse proxy and the application add the header. Browsers act on the first one only, which may well be the weaker policy. Keep HSTS in one place.
- The redirect from
https://example.comtohttps://www.example.comhas no header. Visitors who typeexample.comstay exposed, sinceincludeSubDomainsonwwwdoes not reach up to the parent domain.
Checking HSTS
Enter your address at ZwoWebCheck. It looks only at what any browser receives and evaluates the first HTTPS response, even when that response is a redirect. The report rates whether the header is valid, how long it lasts and whether it covers subdomains; for a base domain it also lists what is still missing for the preload list.