HSTS (HTTP Strict Transport Security) is a security header that tells browsers to always connect via HTTPS — even if the user types http:// or clicks an HTTP link. Once a browser receives an HSTS header, it automatically upgrades all future requests to HTTPS for that domain, preventing downgrade attacks and insecure connections.
Why HSTS matters
Without HSTS, the first request to your site may be HTTP (before the 301 redirect kicks in). During that brief window, an attacker on the network can:
- Strip HTTPS — intercept the redirect and keep the user on HTTP (SSL stripping attack)
- Steal cookies — if cookies are sent over the initial HTTP request
- Inject content — modify the redirect response
HSTS eliminates this window. After the first HTTPS visit, the browser never tries HTTP again.
How to enable HSTS
Nginx
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
Add this inside your HTTPS server block (port 443), not the HTTP redirect block.
Apache
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"
Requires mod_headers (sudo a2enmod headers).
Cloudflare
Dashboard → SSL/TLS → Edge Certificates → HTTP Strict Transport Security (HSTS) → Enable.
HSTS parameters
| Parameter | Example | Meaning |
|---|---|---|
max-age | 63072000 (2 years) | How long (in seconds) the browser remembers to use HTTPS |
includeSubDomains | — | Applies HSTS to all subdomains too |
preload | — | Signals intent to join the HSTS preload list |
Choosing max-age
| Phase | max-age | Purpose |
|---|---|---|
| Testing | 300 (5 minutes) | Verify HTTPS works before committing |
| Confident | 604800 (1 week) | Low risk if you need to roll back |
| Production | 31536000 (1 year) | Standard recommendation |
| Long-term | 63072000 (2 years) | Required for preload list |
Start small, increase gradually. If HTTPS breaks while a long max-age is cached, visitors can’t access your site at all — the browser refuses to connect over HTTP.
HSTS preload
The HSTS preload list is a list of domains hardcoded into browsers to always use HTTPS, even on the very first visit (before any HSTS header is received).
Requirements for preload
- Serve a valid HTTPS certificate
- Redirect HTTP to HTTPS on the same host
- HSTS header with
max-age≥ 63072000 (2 years) - Include
includeSubDomainsdirective - Include
preloaddirective
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
Submit for preload
Go to hstspreload.org, enter your domain, and submit. After review (weeks to months), your domain is added to browsers’ built-in lists.
Warnings about preload
- It’s hard to undo. Removal from the preload list takes months and requires a browser release cycle. During that time, your domain can only be accessed over HTTPS.
includeSubDomainsis mandatory — every subdomain must support HTTPS. Ifstaging.example.comdoesn’t have a cert, it becomes inaccessible.- Only preload if you’re certain all current and future subdomains will support HTTPS.
Common mistakes
Setting HSTS on the HTTP response
HSTS must be sent over HTTPS only. If your HTTP redirect also sends the HSTS header, browsers ignore it (the spec requires HTTPS). Set the header in your port 443 block only.
Forgetting about subdomains
includeSubDomains applies HSTS to all subdomains. If internal.example.com doesn’t have HTTPS, it becomes unreachable. Audit all subdomains before enabling.
Setting max-age too high too soon
If HTTPS breaks (expired cert, config error), visitors can’t fall back to HTTP. Their browser refuses to connect. Start with 5 minutes, verify everything works, then increase to 1 year.
How to check if HSTS is active
curl -sI https://yourdomain.com | grep -i strict-transport
# Expected: strict-transport-security: max-age=63072000; includeSubDomains
In Chrome DevTools: Network tab → click the request → Headers → look for Strict-Transport-Security.
Frequently asked questions
Does HSTS replace HTTP→HTTPS redirects?
No. HSTS and redirects serve different purposes. The redirect catches the first HTTP request. HSTS tells the browser to never make HTTP requests again (after the first HTTPS visit). You need both.
Can HSTS cause problems?
Yes, if HTTPS breaks. With a long max-age, browsers refuse to connect over HTTP as a fallback. This is why you should start with a short max-age and only increase once HTTPS is stable.
Do I need HSTS if I’m on Cloudflare?
Cloudflare handles the visitor→Cloudflare connection, but HSTS on your origin protects the full chain. Enable HSTS through Cloudflare’s dashboard for the edge, and on your origin if you use Full (Strict) mode.
What’s the difference between HSTS and the upgrade-insecure-requests CSP directive?
upgrade-insecure-requests tells the browser to load sub-resources (images, scripts) over HTTPS instead of HTTP — fixing mixed content. HSTS tells the browser to always use HTTPS for the entire domain. They solve different problems and can be used together.