Been looking at implementing HSTS in to one of our sites, hoping to validate it on the preload list. But I can't get my head around how it works with the www. Subdomain.

Our site forces secure www.domain.com using this code in the htaccess.

  <ifModule mod_headers.c>
Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS

<IfModule mod_rewrite.c> 
RewriteEngine on
RewriteCond %{HTTPS} !=on [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

This seems to only send headers when calling the www version.

But when validating, obviously you can't validate a subdomain and it needs to be root TLD. So you get this notice:

www.domain.com is a subdomain. Please preload domain.com instead. (Due to the size of the preload list and the behaviour of cookies across subdomains, we only accept automated preload list submissions of whole registered domains.)

If I remove the "env=https" and add "always" to the htaccess such as :

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

I then get it being used across both www and non www but it still doesnt validate as i get this warning:

Warning: Unnecessary HSTS header over HTTP, The HTTP page at domain.com sends an HSTS header. This has no effect over HTTP, and should be removed.

So im stuck as to what I've done wrong, or what i need to do next to make it validate.

Any help appreciated.

Please note. This is a standard Apache server, using htaccess ( because its a shared environment. Using Cpanel.

  • 1
    Why not keep the second case but put your Header set... only in the HTTPS VirtualHost for the "top" site, so that it will not apply to the HTTP ones nor the subdomains? May 15, 2018 at 17:36

2 Answers 2


using htaccess ( because its a shared environment. Using Cpanel.

Aside: I would be wary about "preload list submission" on a shared server, since you don't have complete control (and it is easier / less prone to error to implement this in the main server config).

Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HTTPS

In the code you posted, the header would never be set because the HTTPS environment variable is never actually being set. Note that this is different from the HTTPS server variable as used in the RewriteCond directive later in the code. (But the HTTPS server variable is always set, so that wouldn't work here anyway.)

(It's possible that the host themselves is setting this env var, but that is not clear here and in any case, it is likely to always be set; mimicking the HTTPS server variable.)

It's also possible that you are actually setting this header in your application code (as well). This would explain why you are seeing this header on www only.

Anyway, to implement this in .htaccess you could do something like the following:

RewriteEngine on

# Set HSTS env var only if HTTPS
RewriteCond %{HTTPS} on
RewriteRule ^ - [E=HSTS:1]

# Redirect HTTP to HTTPS on the same host
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Redirect non-www to www (HTTPS only)
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Set HSTS header conditionally if request is over HTTPS only (based on HSTS env var)
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" env=HSTS

The always condition is required on the Header directive so the header is set on non-200 OK responses. ie. it needs to be set on the non-www to www HTTPS 301 redirect.

I used an HSTS environment variable, rather than HTTPS to avoid confusion with the HTTPS Apache server variable (also used here and noted above) and because some shared hosts also set an HTTPS environment variable.

Warning: Unnecessary HSTS header over HTTP, The HTTP page at domain.com sends an HSTS header. This has no effect over HTTP, and should be removed.

Although this is only a "warning". It's not strictly an "error". And as far as I know, this does not violate HSTS (or the HSTS preload list requirements for that matter). Whilst it is indeed "unnecessary" to send the HSTS header over HTTP, this should not be a problem, as any compliant UA simply ignores this header (to prevent MITM attacks) when sent over HTTP. This is the criteria that is stated in RFC 6797, not that it shouldn't be sent over HTTP. So maybe the preload list submission is just trying to protect against potentially compromised / non-compliant UAs in this regard?


HSTS Preload Rules (simplified)

The following redirects should exist for a site that uses www as the canonical URL.

  • http://example.com -> https://example.com [No header]
  • https://example.com -> https://www.example.com [With header]
  • http://www.example.com -> https://www.example.com [No header]

enter image description here

The rules are:

  • HTTP should always redirect to HTTPS on the same URL Source
  • HTTPS should serve the HSTS header Source
  • HTTP should not serve the HSTS header Source

Why didn't your attempts work

The first attempt only serves headers on the www subdomain, breaking the second rule.

The second attempt breaks the third rule, HTTP shouldn't send the HSTS header.

  • 3
    Those requirements are awful. http://example.com would be better to redirect to https://www.example.com to avoid double redirects. May 26, 2018 at 10:07
  • 2
    But then https://example.com wouldn't be visited, so includesubdomains wouldn't apply to the whole domain
    – jrtapsell
    May 26, 2018 at 14:01
  • 2
    The first redirect only happens once per expiry window, after that the http->https is done inside the browser automatically
    – jrtapsell
    May 26, 2018 at 14:18
  • 2
    "HTTP shouldn't send the HSTS header" - The RFC doesn't actually state this. It only states that the UA should ignore such a header if received over HTTP.
    – MrWhite
    Oct 28, 2020 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.