The HSTS header tells a supporting browser to keep using HTTPS for a host after learning its policy over a secure connection. Setting Strict-Transport-Security is a small configuration change with a long-lived effect. Before launch, verify the deployed response, decide which hosts it covers, and test recovery before increasing the policy lifetime.
A developer fixing a missing HSTS header needs more than a value to paste into middleware. A CDN can remove it, an error route can omit it, and a parent-domain policy can reach a forgotten subdomain. This guide walks through a controlled rollout and repeatable checks for a public website.
HSTS header launch checklist
- Confirm valid HTTPS and certificate renewal for each intended host.
- Separate the HTTP redirect check from the HTTPS header check.
- Decide whether the policy covers one host or its subdomains too.
- Start with a short, reviewed
max-ageand monitor the rollout. - Check representative HTTPS documents, redirects, assets, and error responses.
- Assert the approved value after deployment and record the release ID.
- Document how to remove a learned policy and how preload changes recovery.
Use the website security headers checklist for the other browser policies. This article focuses on HSTS delivery, scope, and rollout rather than repeating the full header review.
What Strict-Transport-Security changes
A basic policy looks like this:
Strict-Transport-Security: max-age=300
max-age is the policy lifetime in seconds. Here, 300 means five minutes. Each qualifying HTTPS response with the header refreshes the expiration. Browsers ignore a header delivered over HTTP; adding it to an insecure redirect cannot establish the policy. HSTS also makes certificate failures blocking errors for covered hosts. These behaviors are documented in MDN's Strict-Transport-Security reference.
HSTS is scoped to a hostname, not to the route that sends the header. A policy learned from /docs affects other paths on that host. The browser upgrades covered HTTP URLs before sending the request. RFC 6797's processing rules define host matching and HTTPS rewriting. An ordinary redirect instead requires the client to contact the HTTP server first.
Keep your HTTP-to-HTTPS redirect for clients without a learned policy. Check its destination using the canonical URLs and redirects guide. HSTS does not configure your server's certificate or repair an unavailable HTTPS endpoint.
Choose host coverage before includeSubDomains
Write down the actual hostnames before changing the policy. For a student portfolio, that might be example.com, www.example.com, and demo.example.com. A product can also have support, status, uploads, and vendor-managed hosts.
For each one, record its owner, HTTPS result, certificate renewal process, and whether it must remain active. Check nested and internal web hosts when considering a parent policy. A DNS inventory alone does not tell you whether a vendor's custom-domain endpoint works over HTTPS.
includeSubDomains extends a host's policy downward. A policy on example.com can cover www.example.com; a policy on www.example.com does not cover its parent or sibling api.example.com. MDN's subdomain guidance also explains that a subdomain may store its own policy independently.
If your apex HTTPS URL redirects to www, inspect the apex redirect response as well as the final document. The destination's header does not establish the apex host's policy. Serve a deliberate header on each HTTPS host you own instead of assuming one redirect chain covers the whole domain.
Until the subdomain review is complete, a host-only policy gives you a narrower rollout. Add includeSubDomains only when the expanded HTTPS contract is supported. Keep future subdomain provisioning tied to that contract too.
Roll out HSTS max-age in stages
Treat these as example stages for a host-only rollout, not a universal production policy:
# Initial observation: five minutes
Strict-Transport-Security: max-age=300
# Later stage: one week
Strict-Transport-Security: max-age=604800
# Later stage: one month
Strict-Transport-Security: max-age=2592000
Deploy one value at a time. Record the value, host scope, deployment time, and owner. During the observation window, exercise the site's important routes and watch certificate, routing, and availability failures. Define who can stop promotion if a host fails.
The HSTS preload site's deployment recommendations describe staged lifetimes and waiting through each stage before progressing; their examples include subdomains after those hosts have been verified. Use that approach to plan the rollout rather than immediately copying a year-long policy into an untested deployment.
Keep preload out of the initial configuration. The preload guidance currently recommends HSTS while advising against preloading. If your team separately chooses it, review the current requirements, submission, and removal process. Adding the token does not prove inclusion in browser lists, and removal depends on browser updates rather than your next deployment alone.
Fix a missing HSTS header at the response layer
Choose the layer that owns the public HTTPS response: your edge platform, reverse proxy, or application. Check the delivered response before editing code. The origin can send the right value while a proxy overrides it, or application middleware can miss a static route.
For an existing Nginx HTTPS server block, the relevant directive is:
# Inside the HTTPS server block; TLS is configured separately.
add_header Strict-Transport-Security "max-age=300" always;
Nginx's `add_header` documentation explains that always applies the header regardless of response status. Under its default inheritance rules, a location with its own add_header directives can lose the parent headers. Review nested locations and any configured inheritance behavior before assuming coverage.
For managed hosting, use the platform's response-header configuration and verify whether it covers dynamic routes as well as static files. For application middleware, include error handling in the review. Avoid competing policies at several layers; establish one approved value and inspect what reaches the browser.
Do not put HSTS in an HTML meta tag. RFC 6797 section 8.5 excludes that mechanism from establishing the policy.
Test the HSTS header with GET requests
Inspect an HTTPS response without following redirects first:
curl -sS --dump-header - --output /dev/null https://example.com/
Repeat for a representative document, an HTTPS redirect route, a static asset, and a known missing route. Expect the right status for each case; a real 404 should stay a 404 while delivering the approved header.
Check the insecure entry point separately:
curl -sS --dump-header - --output /dev/null http://example.com/
Inspect its status and Location, then request the HTTPS destination explicitly. If you use --location to follow a chain, keep each header block associated with its host and status. A match anywhere in the output is not enough to prove which response delivered the policy. The curl manual documents these options. These commands use GET rather than HEAD to inspect the method used for ordinary document retrieval.
Leave certificate verification enabled. Do not add --insecure to make a failing release check pass. Save the URL, status, observed header, and build revision so a later header regression has reproducible evidence.
Add a focused HSTS testing contract to CI
Once your team approves the serialized value, test it exactly. This Playwright example checks three HTTPS response types without following redirects:
import { expect, test } from "@playwright/test";
const origin = "https://preview.example.com";
const expectedPolicy = "max-age=300";
const cases = [
{ path: "/", status: 200 },
{ path: "/docs", status: 200 },
{ path: "/__hsts-check-missing__", status: 404 }
];
for (const entry of cases) {
test(`HSTS response contract: ${entry.path}`, async ({ request }) => {
const response = await request.get(new URL(entry.path, origin).href, {
maxRedirects: 0,
failOnStatusCode: false
});
expect(response.status()).toBe(entry.status);
expect(response.headers()["strict-transport-security"])
.toBe(expectedPolicy);
});
}
Replace the host, routes, statuses, and policy with your deployment contract. If /docs intentionally redirects, assert that response and its Location, then test the destination in another case. Add known assets and other response layers when relevant. Playwright's APIRequestContext documentation describes redirect and status handling.
Run this after the preview is available and again against the public release. A preview hostname can have a different edge configuration. Update the expected policy only through a reviewed change when promoting a rollout stage.
This checks response delivery; it does not test a browser's remembered HSTS state or preload membership. Follow the website regression testing guide to retain evidence and distinguish a confirmed policy change from a failed measurement.
Diagnose cached policies and plan rollback
If a browser upgrades a URL while your server no longer sends HSTS, compare delivered headers with the browser's existing state. Removing the header does not immediately delete a learned policy. A valid HTTPS response with max-age=0 removes that host's stored policy; independently stored subdomain policies and inherited coverage need separate consideration. RFC 6797's policy storage rules explain these limits.
A rollback therefore needs working HTTPS. If the certificate is broken, affected browsers cannot safely receive the removal header. Restore the certificate and secure service first. Do not treat disabling HTTPS as a rollback.
Keep the recovery owner, configuration location, and covered-host list in the release notes. Test delivered headers and browser navigation separately. Also check mixed content errors: transport policy on your host cannot make an unrelated insecure asset endpoint available.
Verify the public release with Slop Audit
Run a Slop Audit on the deployed public URL after configuring HSTS. The report records the observed Strict-Transport-Security value and checks its presence alongside HTTPS, other response headers, crawl controls, and bounded browser evidence. Use the finding to identify a response-layer gap, deploy the fix, and rescan the same route.
Slop Audit's HSTS rule checks presence. It does not validate max-age, audit every subdomain, inspect browser policy stores, verify preload membership, or certify transport security. Even max-age=0 can satisfy a presence check while removing a learned policy. Keep your approved-value tests and host inventory beside the report when signing off the launch.