HSTS, short for HTTP Strict Transport Security, is a response header that tells a browser: from now on, only use HTTPS to reach this site. The browser remembers the instruction for the time you set. Even if someone types http://example.com or follows an old link, the browser upgrades the request to HTTPS itself before sending anything.
That is a real security gain, and also a commitment. Once a browser has stored the policy, it will refuse to connect when your certificate is expired, mismatched or broken, and the visitor cannot click through the warning. A rushed rollout can lock people out of a subdomain you forgot about. This guide walks through a staged HSTS rollout: confirm HTTPS works everywhere, send a short policy first, lengthen it in steps, and decide carefully about the preload list.
It is for site owners and developers who control the web server, CDN or application configuration. At the end you will have a correct Strict-Transport-Security header in place, a way to verify it, and a plan for the long-term policy.
Before you begin
HSTS sits on top of a working HTTPS setup. Before you start:
- Every page on the host loads over HTTPS with a valid certificate. If you see errors, fix them first with SSL certificate errors.
- Plain HTTP requests redirect to HTTPS with a 301. HTTP to HTTPS migration covers the order of work.
- You have a list of every subdomain in use, including internal ones, test sites, mail or admin hosts and old marketing domains. Check DNS for records you forgot.
- Mixed content is fixed. See mixed content on HTTPS pages.
- Certificate renewal is automatic or monitored. If a certificate lapses under HSTS, visitors cannot bypass the error.
- You can edit server configuration or have someone who can. Back it up first.
Allow a few weeks for the full rollout, mostly waiting between stages. The edit itself takes minutes.
HSTS does not make a site more secure in every respect, it does not replace other security headers (see HTTP security headers), and it is not a search ranking feature you can count on.
How the header works
The header has one required directive and two optional ones. According to MDN:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
max-ageis required. It is the time in seconds that the browser should remember that the host is only to be reached over HTTPS.includeSubDomainsis optional. It extends the policy to all subdomains of the host's domain.preloadis optional. It signals that you want to be in browsers' built-in preload lists, covered below.
Some behaviours matter for planning.
- The header is honored only over HTTPS. Browsers ignore it when it arrives over plain HTTP, which stops an attacker in the middle from adding or expiring it. Do not bother adding it to the HTTP redirect response.
- It affects future requests. The header does not change how the browser handles the current response; it changes how it makes later requests.
- There is no click-through. For a known HSTS host, if a TLS error such as an invalid certificate occurs, the browser does not offer a way to proceed.
- Each response resets the clock. Every time the browser receives the header it sets the expiry to now plus
max-age. If a later response lacks the header, the earlier policy remains in effect until it expires. - It is stored per domain name and applies to all ports. An IP address cannot be an HSTS host.
max-age=0removes the policy, but only once the browser makes a secure request and receives that header. You cannot disable HSTS over insecure HTTP.- First visits are not protected. HSTS takes effect only after the browser has made at least one secure connection and received the header. The first request, if it is plain HTTP, remains exposed. Preloading is the answer to that, with trade-offs.
Step-by-step instructions
Step 1: Audit every host and subdomain
Make a table of hosts under your domain: www, the bare domain, blog, shop, mail, staging, old, and any internal names. For each, record whether it answers on HTTPS, has a valid certificate and redirects HTTP to HTTPS.
This step matters most if you plan to use includeSubDomains. The policy then applies to all present and future subdomains, which MDN describes as blocking access to anything that can only be served over HTTP. If one forgotten subdomain is HTTP-only, it will stop working for visitors who have stored your policy.
What success looks like: Every host in the table works over HTTPS, or you have decided to leave includeSubDomains out for now.
Step 2: Confirm the redirect and fix any problems
Request the HTTP version of a page and confirm you receive a permanent redirect to the HTTPS URL:
curl -sI http://example.com/ | head -n 5
curl -sI https://example.com/ | head -n 10
The first should return a 301 with a Location header beginning https://. MDN advises hosts that accept HTTP to answer with a permanent redirect such as 301 pointing to an https URL, and says the redirect must not carry the HSTS header; the HTTPS response that follows should. Avoid long redirect chains, covered in redirect chains and loops.
What success looks like: HTTP returns a single 301 to the same path on HTTPS, with no HSTS header on the HTTP response.
Step 3: Send a short policy first
The hstspreload.org site recommends increasing max-age in stages, and gives these as examples:
- Five minutes:
max-age=300 - One week:
max-age=604800 - One month:
max-age=2592000
Add includeSubDomains at each stage only if you checked every subdomain in Step 1. At each stage, watch for broken pages, track site metrics, fix problems, and wait the full max-age before moving up.
ASP.NET Core's documentation gives similar advice for first-time HTTPS: set the initial max-age to a small value, from hours to no more than a single day, in case you need to revert, then increase it once you are confident. A commonly used value afterwards is one year.
Add the header to every HTTPS response. Examples for common setups follow.
nginx. The always parameter adds the header regardless of the response code. Without it nginx adds the field only for a list of success and redirect codes:
server {
listen 443 ssl;
server_name example.com;
add_header Strict-Transport-Security "max-age=300" always;
}
nginx has an inheritance trap: add_header directives are inherited from the previous level only if there are none at the current level. If you define any add_header inside a location block, repeat this one there, or use add_header_inherit merge where your version supports it.
Apache. Header always set adds the header to all responses, including errors, which plain Header set does not:
<VirtualHost *:443>
ServerName example.com
Header always set Strict-Transport-Security "max-age=300"
</VirtualHost>
This requires mod_headers to be enabled.
ASP.NET Core. Use the built-in middleware, and only outside development. Microsoft's documentation says UseHsts is not recommended in development because browsers cache HSTS settings heavily, and that by default it excludes the loopback hosts localhost, 127.0.0.1 and [::1]:
builder.Services.AddHsts(options =>
{
options.MaxAge = TimeSpan.FromMinutes(5);
options.IncludeSubDomains = false;
});
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
The documented default max-age for UseHsts is 30 days, so set it explicitly during the first stage. On a CDN or hosting platform, look for an HSTS toggle in its security or SSL settings, and read what it sets before enabling it.
What success looks like: An HTTPS response includes Strict-Transport-Security: max-age=300, and the site works normally.
Step 4: Verify the header
Check the header on several pages, including a 404 page and a redirect from HTTPS if you have one:
curl -sI https://example.com/ | grep -i strict-transport-security
curl -sI https://example.com/missing-page | grep -i strict-transport-security
Both should show the header. A 404 without it points to a missing always condition. In Chrome, you can also open DevTools, go to the Network panel and select the document request to read its response headers.
Remember that a browser that stored the policy now upgrades http:// to https:// itself. If you test with the same browser later, you may see an internal redirect that never reached your server. Use curl for server-side checks.
What success looks like: The header appears on pages, errors and other response types, and nothing else on the site broke.
Step 5: Lengthen the policy gradually
Move to one week, then one month, then at least a year, following the staged approach above. Wait the full time of each stage before advancing, because browsers that stored the older policy keep it until it expires and each visit refreshes the timer.
A common long-term value is one year:
Strict-Transport-Security: max-age=31536000; includeSubDomains
MDN says this makes all present and future subdomains HTTPS-only for a year. If you cannot promise that, leave out includeSubDomains and send the header from each subdomain that supports HTTPS. MDN notes that each subdomain should send its own header, because a browser may contact a subdomain before the parent domain.
What success looks like: The long policy has been live, without complaints or broken hosts, for at least one full stage period.
Step 6: Decide about preloading
Preloading puts your domain in lists shipped inside browsers, so the very first visit is HTTPS too. It is not part of the HSTS specification and should not be treated as official, MDN says, although all browsers use the list hosted by Google.
hstspreload.org lists the requirements: serve a valid certificate; redirect from HTTP to HTTPS on the same host if you listen on port 80; serve all subdomains over HTTPS, including www if its DNS record exists; and send an HSTS header on the base domain's HTTPS responses with max-age of at least 31536000 (one year), plus includeSubDomains and preload. Its example is:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Its warnings are serious: inclusion cannot easily be undone, removal can take months to reach Chrome users, and other browsers give no assurance. It says not to request inclusion unless you are sure you can support HTTPS for your entire site and all subdomains for the long term. It also states that HSTS is recommended but preloading is not.
So preload is optional. Choose it only after months of stable HTTPS everywhere. Many sites run HSTS with a one-year max-age and never preload.
What success looks like: You have made and written down an explicit decision, with the owner who accepted the long-term commitment.
Step 7: Set up monitoring
Expired certificates are the main risk. Add alerts for certificate expiry and for the HSTS header disappearing from a key page. Include HSTS in your release checks, and keep a rollback note: to remove the policy, send max-age=0 over HTTPS, and expect it to apply only for browsers that return and receive it.
What success looks like: You get an alert before a certificate expires, and the team knows how a rollback works.
Final verification checklist
- All hosts under the domain (or those in scope) work over HTTPS with valid certificates.
- HTTP requests return a 301 to the HTTPS URL with no HSTS header on the HTTP response.
- The HTTPS response carries
Strict-Transport-Securityon pages and on error responses. -
includeSubDomainsis used only after every subdomain was checked. -
max-agewas increased in stages with a full wait at each stage. - The header is not set in local development configuration.
- Certificate renewal is automated or monitored.
- A decision on preloading is recorded, with its long-term commitment understood.
- The rollback procedure (
max-age=0over HTTPS) is written down.
Common mistakes to avoid
- Starting with a one-year
max-age. If something is wrong, you cannot undo it for returning visitors quickly. Start at five minutes. - Adding
includeSubDomainswithout an audit. An HTTP-only subdomain becomes unreachable. Check every subdomain first. - Sending the header over HTTP. Browsers ignore it there. Send it on HTTPS responses.
- Missing the
alwaysor error cases. nginx and Apache can skip the header on errors by default. Usealways. - Losing the header through nginx inheritance. A single
add_headerin alocationblock can switch off inherited ones. Repeat it or use the merge option. - Enabling HSTS in development. Browsers cache the policy heavily, and local hosts can break. Keep it out of development.
- Requesting preload on impulse. Removal is slow. Only submit after long-term certainty about HTTPS on all subdomains.
- Letting a certificate expire under HSTS. Visitors cannot click through. Monitor renewal.
Frequently asked questions
Does HSTS improve SEO?
It makes sure browsers use HTTPS for your site. No guide can promise a ranking benefit from the header, so treat it as a security control and judge it on that.
What max-age should I use?
Use the staged approach: five minutes, one week, one month, then at least one year. A year is also the minimum the preload list requires.
Can I turn HSTS off if there is a problem?
You can send max-age=0 over HTTPS. It takes effect only once a browser makes a secure request and receives that response, so visitors who never return keep their old policy until it expires. Plan as if the policy cannot be reversed quickly.
Does the header need to be on the redirect from HTTP?
No. Browsers ignore it over HTTP. The redirect should be a plain 301 to the HTTPS URL, and the HTTPS response carries the header.
Do I need preload?
No. hstspreload.org itself says HSTS is recommended but preloading is not. It protects the first visit, but it is hard to undo, so adopt it only with a long-term commitment to HTTPS.
Related guides
- SSL Certificate Errors: Diagnose Expired, Mismatched and Incomplete
- HTTP to HTTPS Migration: Move Your Site to HTTPS in the Right Order
- Add HTTP Security Headers: CSP, nosniff, Referrer-Policy and More
- Fix Mixed Content: Remove http:// Resources From HTTPS Pages
- Redirect Chains, Loops, and Incorrect HTTP Status Codes
Official references
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security
- https://hstspreload.org/
- https://learn.microsoft.com/en-us/aspnet/core/security/enforcing-ssl
- https://nginx.org/en/docs/http/ngx_http_headers_module.html
- https://httpd.apache.org/docs/current/mod/mod_headers.html
Next step: See how Crawvix checks a website and capture a baseline once scanning opens. This guide provides technical information, not a guarantee of rankings, traffic or index inclusion.
Crawvix Editorial Team
· Published October 29, 2026 · Last updated October 29, 2026 · 11 min read