HTTP Strict Transport Security (HSTS) is one of the most effective, yet frequently misconfigured, web security headers available. This guide is for developers, DevOps engineers, and technical managers who want to enforce HTTPS across their entire site and protect users from protocol downgrade attacks, SSL stripping, and cookie hijacking. Follow these steps in order — skipping ahead can lock visitors out of your site.
Ensure Full HTTPS Coverage Before Enabling HSTS
HSTS tells browsers to never connect to your site over plain HTTP. If any part of your site still relies on HTTP — even a single image, script, or redirect — enabling HSTS can break those resources permanently for returning visitors. Fix all mixed-content issues first.
- Obtain and install a valid TLS/SSL certificate from a trusted Certificate Authority (CA) for your domain and all subdomains you plan to cover.
- Ensure your web server redirects all HTTP traffic (port 80) to HTTPS (port 443) with a 301 permanent redirect.
- Audit every page for mixed content: open browser developer tools, go to the Console tab, and look for warnings about insecure resources loaded on HTTPS pages.
- Update all hardcoded
http://URLs in your HTML, CSS, JavaScript, and database records tohttps://or protocol-relative//URLs. - Verify third-party embeds, fonts, analytics scripts, and CDN assets all load over HTTPS.
- Confirm your SSL certificate is valid, not expired, and covers all hostnames (including
wwwand any other subdomains you use).
Add the Strict-Transport-Security Header to Your Server
The HSTS policy is delivered via the Strict-Transport-Security HTTP response header. It must be sent only over HTTPS — browsers ignore the header if received over HTTP. Below are configuration examples for the most common web servers.
- Apache: Add the following inside your HTTPS
<VirtualHost>block (requiresmod_headersenabled):Header always set Strict-Transport-Security "max-age=300" - Nginx: Add the following inside your HTTPS
serverblock:add_header Strict-Transport-Security "max-age=300" always; - IIS: Add a custom HTTP response header named
Strict-Transport-Securitywith valuemax-age=300via IIS Manager → HTTP Response Headers, or inweb.config:<customHeaders><add name="Strict-Transport-Security" value="max-age=300" /></customHeaders> - Node.js / Express: Use the
helmetmiddleware:app.use(helmet.hsts({ maxAge: 300 })); - Caddy: HSTS is enabled automatically when you configure an HTTPS site in your Caddyfile, but you can customise it with:
header Strict-Transport-Security "max-age=300" - After deploying, use your browser's developer tools (Network tab → select any response → Headers) to confirm the header appears on HTTPS responses.
Configure the max-age Directive Progressively
The max-age value (in seconds) tells browsers how long to remember the HSTS policy. Start low during testing so you can easily recover from misconfigurations. Once confident, ramp up to the production-recommended value. Remember: once a browser caches a long max-age, it will enforce HTTPS for that duration — even if you later remove the header.
- Start with
max-age=300(5 minutes) in a staging environment to verify the header works without breaking anything. - After staging validation, deploy to production with
max-age=86400(1 day) and monitor for any user-reported issues. - After one week of stable operation, increase to
max-age=2592000(30 days). - After a month of clean operation, set the final production value to
max-age=31536000(1 year) — this is required for HSTS preload list submission. - Document the current
max-agevalue and its expiry date in your security runbook so the team knows when HSTS caches expire.
Extend Protection with the includeSubDomains Directive
By default, HSTS only protects the exact domain that sends the header. Adding includeSubDomains extends the policy to every subdomain (e.g., api.example.com, mail.example.com). Do not add this directive until every subdomain is serving valid HTTPS — any subdomain still on HTTP will become completely unreachable for users whose browsers have cached the policy.
- Inventory all subdomains (including ones used internally, for APIs, email, or staging) and verify each has a valid HTTPS certificate.
- Decommission or redirect any HTTP-only subdomains to HTTPS, or move them to a separate domain not covered by HSTS.
- Update your HSTS header to include the directive:
Strict-Transport-Security: max-age=31536000; includeSubDomains - Test each subdomain in a browser to confirm HTTPS is enforced and no certificate errors appear.
Enable the preload Directive and Submit to the HSTS Preload List
Browser-cached HSTS only protects users after their first visit. The HSTS Preload List is a hardcoded list maintained by browser vendors (Chrome, Firefox, Safari, Edge) that enforces HTTPS for listed domains even on a user's very first request — eliminating the initial HTTP window entirely. Submission is irreversible in the short term, so only proceed once your max-age and includeSubDomains are stable.
- Ensure your HSTS header includes all three components:
max-age=31536000; includeSubDomains; preload. - Confirm your
max-ageis at least31536000(1 year) — this is a hard requirement for preload list eligibility. - Visit hstspreload.org, enter your domain, and verify it passes all eligibility checks before submitting.
- Submit your domain. Note that inclusion in the preload list can take several weeks and affects all browsers that ship with the list.
- Understand that removal from the preload list also takes weeks to propagate — plan accordingly before submitting.
- After submission, monitor hstspreload.org periodically to confirm your domain's status moves from "pending" to "preloaded".
Test and Validate Your HSTS Configuration
Deploying HSTS without validation is risky. Use multiple methods to confirm the header is correctly set, that HTTPS redirects work, and that no mixed content remains. Sensagraph automatically checks for the presence and correctness of the HSTS header as part of its continuous security scanning.
- Open your site in Chrome, press F12 to open DevTools, go to the Network tab, reload the page, click any request, and verify the
Strict-Transport-Securityheader appears in the response headers with the correct value. - In Chrome, navigate to
chrome://net-internals/#hsts, enter your domain in the "Query HSTS/PKP domain" field, and confirm it is listed with the expected policy. - Test that
http://yourdomain.comredirects tohttps://yourdomain.comwith a 301 response (not a 302). - Use
curl -I https://yourdomain.comfrom the command line to inspect response headers directly. - Verify the header is absent on HTTP responses (it should only appear on HTTPS).
- Re-check for mixed content after any content updates or new third-party integrations.
- Use securityheaders.com or SSL Labs to get an independent assessment of your security headers and TLS configuration.
Monitor, Maintain, and Plan for Certificate Renewals
HSTS is not a set-and-forget control. If your TLS certificate expires while HSTS is enforced, users will be locked out of your site with no way to bypass the error (unlike a normal certificate warning, HSTS errors cannot be clicked through). Robust monitoring is essential.
- Set up automated certificate renewal using Let's Encrypt with Certbot, AWS Certificate Manager auto-renewal, or your CA's equivalent — and test that auto-renewal actually works before relying on it.
- Configure alerts to notify you at least 30 days before your TLS certificate expiry date.
- Add HSTS header verification to your uptime monitoring or CI/CD pipeline so you know immediately if it disappears after a server change.
- Review your HSTS configuration after any major infrastructure change: server migrations, CDN changes, load balancer updates, or new subdomain deployments.
- Include HSTS header status and certificate expiry dates in your regular security review cycle. Sensagraph continuously monitors your HSTS header and flags misconfigurations or regressions automatically.
- Document your rollback plan: know what the consequences are of lowering
max-ageor removing the header, and how long it will take for cached policies to expire in user browsers.