Blog
3 min read

What Is HSTS? Strict-Transport-Security Explained

HSTS tells browsers to only ever use HTTPS for your site, closing the gap where a first HTTP request could be intercepted. How the header works, max-age, includeSubDomains and preload, how to roll it out safely, and how to set it in Nginx, Caddy, Express and Next.js.

HSTS (HTTP Strict Transport Security) is a response header that tells browsers:

"For this site, only ever use HTTPS. Don't even try plain HTTP."

Strict-Transport-Security: max-age=31536000; includeSubDomains

The problem it solves

Your site uses HTTPS, and redirects http:// to https://. But when someone types example.com or follows an old http:// link, the browser's first request goes out unencrypted. Someone on the same network can intercept that request and keep the user on a fake HTTP version of your site — an "SSL stripping" attack. (Man-in-the-middle attacks)

With HSTS, after the browser has seen the header once, it rewrites every http:// request for your site to https:// itself, before anything goes over the network. It also stops users clicking through certificate warnings for your site.

The header's parts

Part Meaning
max-age=31536000 Remember this rule for this many seconds (here, one year)
includeSubDomains Apply it to every subdomain too
preload You're asking to be on browsers' built-in HSTS list

Rolling it out safely

HSTS is hard to undo: browsers remember it for the whole max-age. If some part of your site — or a subdomain — can't do HTTPS, visitors with HSTS cached simply can't reach it.

So roll it out gradually:

  1. Make sure HTTPS works everywhere — every page, every subdomain you'll include. (How automatic SSL works)
  2. Start short: max-age=300 (5 minutes). Check nothing breaks.
  3. Increase: a week (604800), then a month, then a year.
  4. Add includeSubDomains only once you're sure every subdomain — including old ones, like legacy.example.com or mail.example.com — serves HTTPS.
  5. Consider preload last.

Preloading

Browsers ship with a built-in list of HSTS sites, so even the very first visit uses HTTPS. You can submit your domain at hstspreload.org. Requirements include max-age of at least a year, includeSubDomains and preload in the header.

Preloading is a strong commitment — removal takes a long time to reach users' browsers. Do it when you're confident every subdomain will always have HTTPS. Some domain extensions, like .dev and .app, are on the preload list as a whole, so HTTPS is mandatory for them anyway. (.com vs .io vs .ai vs .app)

Setting it

Only send HSTS over HTTPS responses (browsers ignore it over HTTP).

Nginx:

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

Caddy:

header Strict-Transport-Security "max-age=31536000; includeSubDomains"

Express (Helmet sets HSTS by default):

app.use(helmet({ hsts: { maxAge: 31536000, includeSubDomains: true } }))

Next.js — add it in headers() in next.config.js.

Cloudflare — SSL/TLS → Edge Certificates → HTTP Strict Transport Security.

(HTTP security headers explained)

Checking it

curl -sI https://example.com | grep -i strict

Or DevTools → Network → your page → Response Headers.

Testing gotcha

If you set HSTS on localhost or a staging domain by accident, your browser will refuse HTTP for it. In Chrome, clear it at chrome://net-internals/#hsts (Delete domain security policies).


EasySpawn serves every app over HTTPS with certificates issued and renewed automatically — the prerequisite for turning HSTS on with confidence. See how it works or join the waitlist.

Related: What Is HTTPS? · HTTP Security Headers Explained · Man-in-the-Middle Attacks · Mixed Content Errors

Keep reading