tl;dr There is something else in your code base that is redirecting. The directives you have posted in the question do not (fully) explain the output you are seeing. In fact, the directives you posted from your .htaccess
file may not even be getting processed at all...
(This answer is really in addition to @Stephen's answer and attempts to explain - or question - the results you are seeing.)
When I use these lines in my .htaccess
file, everything works well:
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^(.*)$ https://example.com%{REQUEST_URI} [L,R=301]
"everything works well" - Well, these directives can only be responsible for the first two scenarios you mention (ie. from HTTP):
http://www.example.com
to https://example.com
http://example.com
to https://example.com
However, these directives won't redirect from https://www
(third scenario), as you appear to suggest. They don't canonicalise the www subdomain. Something else is performing this redirection.
I just replaced the domain with {HTTP_HOST}
. When I do that, it redirects from http://www.example.com
to http://example.com
(since it is my main domain) then http://example.com
to https://example.com
.
Given the directive you posted; this is impossible! Your directive only ever redirects to https
, so "something else" must be triggering the first redirect you are seeing to http
. (But there should be nothing that occurs before your .htaccess
redirect - other than in the main server config, or possibly another .htaccess
file, but I assume nothing like that has changed?)
It's possible you are seeing a cached redirect, but you say that you "just replaced the domain with {HTTP_HOST}
", so that kind of rules out the cache.
If I add this line: RewriteCond %{HTTP_HOST} !^www\. [NC]
it does not change anything.
Well, that should definitely have changed the additional redirect you were seeing above (assuming you added it somewhere before the RewriteRule
directive). So, if this didn't do anything then it further suggests that "something else" is performing these redirects and perhaps your directives are not being processed at all!
However, you're suggesting that this additional redirect only started after you "replaced the domain with {HTTP_HOST}
" - which appears to be impossible. So, something else must also have changed.
Some of this could be explained with having placed these directives in the wrong order in your .htaccess
file. For example, if you were using WordPress (or another CMS that uses a front-controller pattern) and you placed your redirects at the end of the file then for most page requests it won't get processed. But, depending on your config, it might still get processed for your homepage and your static resources.
Any redirects of this nature need to go at the very start of your .htaccess
.
And make sure you are not mixing mod_alias Redirect
(or RedirectMatch
) directives with mod_rewrite RewriteRule
. This can result in unexpected conflicts.
...how can I fix the .htaccess
file to not having to manually write the URL and directly redirect http://www.example.com
to https://example.com
?
Aside: If you are intending to implement HSTS then, ironically, you'll need to redirect in two steps (using HTTP_HOST
as above). The first redirect goes to HTTPS on the same host, optionally followed by a canonical www/non-www redirect on HTTPS.
To redirect in a single redirect, you don't necessarily need to use the server-config as @Stephen suggests in his answer (although that is a possibility). But if you have access to the server config then there are altogether better ways to do this using mod_alias Redirect
and <VirtualHost>
containers (quicker and arguably "simpler") - no need for mod_rewrite at all.
However, you can implement this as a single redirect (both HTTP to HTTPS and www to non-www) in .htaccess
using something like the following:
RewriteEngine On
RewriteCond %{HTTPS} !on [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)\.?$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=302,L]
The above states... for all requests that are either not-HTTPS or where the requested hostname starts www.
then redirect to https://<hostname-less-www-prefix>/<URL-path>
. This also removes an optional trailing dot in the case of FQDN. The third condition is necessary in order to capture the hostname, less the (optional) www.
prefix. This is captured into the %1
backreference.
Note that the above is a 302 (temporary) redirect. Only change this to a 301 (permanent) redirect after you have done your testing and confirmed that it is working OK (to avoid caching issues fogging your tests).
Generalising the directives in this way isn't always the best (or most reliable) solution across systems.
.htaccess
file is stored and how yourexample.com
andwww.example.com
VirtualHost
are configured, but you do not show..htaccess file
and the website files are both stored in/root folder/www/
, www. subdomain is just an alias in this case.