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

> Learn how to correctly configure HTTP Strict Transport Security HSTS headers. Ensure all browser connections are secure and get on the HSTS preload list.

- Repository: [David Dias/Front-End-Checklist](https://github.com/thedaviddias/Front-End-Checklist)
- Tags: how-to-guide
- Published: 2026-03-02

---

**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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/README.md).

## Configuration Examples by Platform

### Nginx

Add the header within your HTTPS server block:

```nginx

# 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:

```apache
<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:

```javascript
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:

```xml
<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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/.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`](https://github.com/thedaviddias/Front-End-Checklist/blob/main/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.