Skip to main content

HSTS: forcing HTTPS to secure your site

Security · 19.04.2026 · 5 min read
Illustration for “HSTS: forcing HTTPS to secure your site”

HSTS (HTTP Strict Transport Security) is a header that instructs the browser to always use HTTPS for your domain, even if the user types http://. It protects against SSL-stripping attacks and accidental navigation over HTTP.

How HSTS works

  1. The browser visits the site over HTTPS for the first time
  2. It receives the Strict-Transport-Security header
  3. It stores the domain in the HSTS list for the max-age period
  4. On the next visit — it automatically opens HTTPS without a redirect from the server

Configuring via .htaccess

<IfModule mod_headers.c>
    # Basic HSTS: 1 year
    Header always set Strict-Transport-Security "max-age=31536000"
    
    # With subdomains included
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
    
    # With preload (to be included in the browser list)
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>

Configuring via Nginx

server {
    listen 443 ssl;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}
⚠️ Start with max-age=300 (5 minutes) for testing. Switch to 31536000 only after you've confirmed HTTPS works perfectly on all subdomains.

HSTS Preload

The preload directive lets you add your domain to the built-in browser lists. This means HTTPS will be enforced even on the first visit (before the header is received):

  • Submit a request at: hstspreload.org
  • Requirements: max-age of at least 1 year, includeSubDomains, valid HTTPS on subdomains
💡 Once added to the preload list, removal takes months. Only add your domain if you're sure HTTPS will be permanent.

Checking HSTS

# curl
curl -I https://example.com | grep Strict

# Or Chrome DevTools:
# Network → your request → Response Headers → Strict-Transport-Security

Common HSTS mistakes explained

  • NET::ERR_CERT_AUTHORITY_INVALID with no "Proceed anyway" button — on an HSTS domain, the browser will not let you bypass a certificate error the way it would on an ordinary site. If the certificate expires or was issued for a different domain, the site becomes completely unreachable, not just "unsafe."
  • net::ERR_SSL_PROTOCOL_ERROR on a subdomain with includeSubDomains enabled — if even one subdomain lacks working HTTPS, the browser still forces a connection to it over HTTPS and gets a connection error instead of a soft fallback to HTTP.
  • net::ERR_TOO_MANY_REDIRECTS — a typical result when the HTTPS redirect is configured both on a CDN or load balancer and on the origin server at the same time: the two redirects loop into each other.
  • A Strict-Transport-Security header sent over a plain HTTP connection must be ignored by the browser per the specification — if the config sends it on both http and https, the very first visit still gets no protection without being on the preload list.
  • The chrome://net-internals/#hsts page — Chrome's built-in tool for checking and manually deleting a browser's local HSTS entry for a specific domain, without waiting for max-age to expire.

max-age values: what to set and when

max-age valueDurationWhen to use itRisk
3005 minutesTesting the setup against real trafficMinimal — rolls back almost instantly
864001 dayThe first production stage after a successful testA mistake can still be fixed within a day
259200030 daysStable HTTPS with no complaintsThe certificate must stay valid for the entire period with no downtime
315360001 yearFinal stage, a mandatory requirement for preloadNo rollback for visitors with an already-cached entry until it expires

When it is too early for HSTS

  • The site still serves part of its traffic over HTTP for legacy integrations — old payment gateways or IoT devices with no TLS support — a long max-age HSTS policy makes those integrations unreachable for every browser client at once.
  • Subdomains are issued to users automatically, such as a SaaS product on a wildcard domain, and not everyone is guaranteed a certificate right away — includeSubDomains will block access to subdomains that are not ready yet.
  • The domain is used for local development or a test environment with a self-signed certificate — a long HSTS duration turns every further certificate experiment into a chore of manually clearing settings in each browser.
  • There is a chance the domain will need to go back to HTTP temporarily — during a migration or a CDN change without TLS termination — the preload list is edited slowly, removal from it takes months, and until then no browser will open the site over HTTP at all.

Verifying that HSTS is really protecting the site

# Check the header and its value
curl -sI https://example.com | grep -i strict-transport-security

# Confirm the HTTP version of the same domain still redirects to HTTPS
curl -sI http://example.com | grep -i location

# In Chrome: chrome://net-internals/#hsts → Query domain → enter the domain

A static_sts_domain field in the query result means the domain is baked into the browser's preload list, not just stored in the local cache after a first visit. These are different states: a cache entry disappears on its own once max-age expires, a preload-list entry does not.

Was this article helpful?
← Back to Knowledge Base Ask Support