...advise RewriteCond %{HTTPS} off
and others have RewriteCond %{HTTPS} on
That wouldn't make sense in the context given as these are obviously opposites (I would be interested to see the full examples you are quoting this from).
However, maybe you mean off
vs !on
? These are equivalent in this context. The !
prefix negates the regex, so that effectively means not "on" (ie. it must be "off").
So, in the context of your directives above, where you are testing whether HTTPS is not active, then the following are equivalent:
# Does the HTTPS server variable contain "off"?
RewriteCond %{HTTPS} off
# Does the HTTPS server variable not contain "on"?
RewriteCond %{HTTPS} !on
The HTTPS server variable is either set to "on" or "off". (Or, it's not set at all - but that is dependent on your server/SSL setup and you will have already discovered that by now.)
Which you use is really just a matter of preference.
Other notes on HSTS and .htaccess
# Redirect to www
RewriteCond %{HTTP_HOST} ^example.com\.com [NC]
RewriteRule (.*) https://www.example.com/$1 [E=HTTPS,R=301,L]
# Security header
Header set Strict-Transport-Security "max-age=63072000; preload; includeSubdomains" env=HTTPS
(I assume the extra .com
in ^example.com\.com
is just a typo? That should be just ^example\.com
.)
E=HTTPS
- The purpose of setting the environment variable HTTPS
on the RewriteRule
redirect is to be able to conditionally set the Strict-Transport-Security
HTTP response header on the canonical (HTTPS only) non-www to www redirect[*1] (ie. https://example.com
to https://www.example.com
) based on the env=HTTPS
check on the Header
directive. However, for this header to be set on the redirect, you'll also need to use the always
keyword on the Header
directive, like so:
Header always set Strict-Transport-Security "max-age=63072000; preload; includeSubdomains" env=HTTPS
As noted in the Apache docs, regarding the use of always
with the Header
directive when setting headers on redirects:
- You're adding a header to a locally generated non-success (non-2xx) response, such as a redirect, in which case only the table corresponding to
always
is used in the ultimate response.
[*1] This header must be set on the redirect in order to satisfy point 4.1 of the HSTS preload submission requirements:
If you are serving an additional redirect from your HTTPS site, that redirect must still have the HSTS header (rather than the page it redirects to).
Just an additional comment on the linked article in the comments below, that states:
The env=HTTPS
environment variable wasn't working as expected. So I used the E=HTTPS
flag on the www redirect to set the env=HTTPS
environment variable on the next request.
The last bit about setting "the env=HTTPS
environment variable on the next request" isn't quite correct. It's setting the HTTPS
environment variable on the current (redirect) response. By the time the "next request" comes about (ie. the browser has responded to the redirect), this environment variable (that was set above) is long forgotten. But this does require the always
keyword to be used on the Header
directive (as mentioned above).
Header always set Strict-Transport-Security "max-age=63072000; preload; includeSubdomains" env=HTTPS
Just a minor point, and maybe this doesn't actually matter, but... I would include the preload
directive at the end of the list of directives. For example:
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" env=HTTPS
The preload
directive is not actually part of the HTTP Strict Transport Security (HSTS) specification. It is only required by the preload list. Other user-agents/browsers do not use this and may not even understand this, so it would be more logical to put this at the end of the list. Some parses might stop as soon as they reach an "invalid" directive?
UPDATE: However, this does not appear to be a complete solution. As it stands, the HSTS response header is only being set on the non-www to www (HTTPS) redirect. It's not being set on any other HTTPS responses, which it would need to be. It's quite possible that this header is being returned by the application itself, but there is no evidence of that here (except that the OP states that it does pass HSTS validation).
For a more complete .htaccess
-only solution see my answer to the following related question: HSTS implementation in .htaccess when using www subdomain