How to Configure HTTP Strict Transport Security (HSTS) Headers Correctly

Add the Strict-Transport-Security response header with max-age=31536000; includeSubDomains; preload to every HTTPS response to force browsers to always use secure connections and qualify for the HSTS preload list.

HTTP Strict Transport Security (HSTS) is a critical security mechanism that prevents protocol downgrade attacks and cookie theft by instructing browsers to communicate with your site exclusively over HTTPS. According to the Front-End Checklist repository by thedaviddias, implementing HSTS is marked as a Medium-priority item that requires careful configuration to avoid permanently blocking users from your site. This guide explains how to configure HSTS headers correctly based on the repository's recommendations at README.md (lines 574-579) and industry standards.

What Is HSTS and How Does It Work

When a browser receives the Strict-Transport-Security header, it caches the directive for the duration specified by the max-age parameter. During this period, the browser automatically rewrites any HTTP requests to HTTPS for the host and optionally its sub-domains, eliminating the window of vulnerability where users might access your site over an insecure connection.

Required HSTS Directives

A complete HSTS configuration requires three key directives:

Directive Purpose Recommended Value
max-age Time in seconds that the browser caches the rule 31536000 (approximately 1 year)
includeSubDomains Extends the policy to all sub-domains includeSubDomains
preload Requests inclusion in browser preload lists preload (optional but recommended)

To qualify for the HSTS preload list maintained by browser vendors, you must use a max-age of at least 31536000 seconds and include the includeSubDomains directive. The Front-End Checklist references these requirements in README.md (lines 574-579), linking to the OWASP cheat sheet for authoritative guidance.

Prerequisites Before Enabling HSTS

Enabling HSTS without proper preparation can permanently block users from accessing your site. Follow these prerequisites:

  1. Serve all content over HTTPS: HSTS has no effect on plain HTTP sites and will break them if enabled prematurely.

  2. Deploy valid TLS certificates: Ensure you have valid certificates for the primary domain and every sub-domain if using includeSubDomains.

  3. Test with short durations first: Configure a short max-age (e.g., 60 seconds) in your staging environment to verify functionality before increasing to one year.

  4. Verify preload eligibility: Use the official preload checker at hstspreload.org before submitting to the preload list, as referenced in the checklist at line 577 of README.md.

Configuration Examples by Platform

Nginx

Add the header within your HTTPS server block:


# Enable HSTS (must be inside a server block that listens on HTTPS)

add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

Apache (httpd)

Configure via the headers module:

<IfModule mod_headers.c>
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>

Express.js (using Helmet)

Implement HSTS middleware in your Node.js application:

const helmet = require('helmet');
const express = require('express');
const app = express();

app.use(
  helmet.hsts({
    maxAge: 31536000,           // 1 year in seconds
    includeSubDomains: true,
    preload: true,
  })
);

IIS (Web.config)

Configure via XML in your Web.config file:

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="Strict-Transport-Security"
             value="max-age=31536000; includeSubDomains; preload" />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>

Common Configuration Pitfalls

Avoid these critical errors when deploying HSTS:

  • Enabling on HTTP-only sites: Adding the HSTS header to sites served only over HTTP will cause browsers to permanently block the site once they attempt to access it over HTTPS and then revert to HTTP.

  • Omitting sub-domain coverage: Forgetting includeSubDomains leaves sub-domains vulnerable to downgrade attacks even when the apex domain is protected.

  • Insufficient max-age values: Setting a very short max-age defeats the security purpose and disqualifies you from preload eligibility. Use at least 31536000 seconds (one year).

  • Incorrect preload removal: If your site is already in the preload list, you cannot simply remove the header. You must first deploy a deprecation period using max-age=0; includeSubDomains; preload before removal can be requested.

Key Files in the Front-End Checklist Repository

Understanding the source files provides context for why HSTS appears in the checklist:

  • README.md (lines 572-579): Lists HSTS as a medium-priority checklist item and provides links to the OWASP cheat sheet and preload checker.

  • .github/workflows/readme-check.yml: Runs automated validation on the README to ensure security recommendations remain current.

  • LICENSE: Provides open-source licensing for any code snippets you might reference from the repository.

Summary

  • Configure Strict-Transport-Security headers only after confirming your entire site serves HTTPS content.
  • Use max-age=31536000 (one year), includeSubDomains, and preload for production deployments intended for the preload list.
  • Test with short max-age values (60 seconds) in staging environments before deploying to production.
  • Verify eligibility at hstspreload.org before requesting preload inclusion.
  • Reference the Front-End Checklist README.md (lines 574-579) for ongoing guidance and links to authoritative resources.

Frequently Asked Questions

What happens if I enable HSTS on a site that doesn't support HTTPS?

If you enable HSTS on a site served only over HTTP, browsers that encounter the header will remember that the site should use HTTPS. When those browsers subsequently try to access your site over HTTPS and fail (because no certificate exists), they will permanently block access to the HTTP version, effectively making your site unreachable. Always ensure HTTPS is fully functional before enabling HSTS.

How long should the max-age value be set to?

For production environments targeting preload list inclusion, set max-age to at least 31536000 seconds (one year). During initial testing, use a short value like 60 seconds to ensure you can correct any misconfigurations without long-term consequences. Once confirmed working, increase to the full one-year duration.

Do I need to include the preload directive?

The preload directive is optional but recommended for public-facing sites that want maximum security. Including it signals to browser vendors that you consent to having your domain hard-coded into their HSTS preload lists. However, this requires meeting specific criteria: a max-age of at least one year and the includeSubDomains directive. Verify your eligibility using hstspreload.org before adding the directive.

Can I remove HSTS once it's configured?

You can remove HSTS headers from your responses, but browsers that have already cached the policy will continue enforcing it until the max-age expires. If your domain is in the browser preload lists, removal requires a deprecation period where you must serve max-age=0; includeSubDomains; preload before the preload maintainers will remove your domain. Plan HSTS implementation as a long-term commitment.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →