I found a lot of similar answers but so far I could not solve the right thing that I want. It seems very easy or maybe somebody already answered but for me it's not working.
I've solved redirect to https on TLD (http://example.com
to https://www.example.com
and https://example.com
to https://example.com
)
But my htaccess code doesn't redirect to https://www.example.com/whatever
from http://example.com/whatever
or https://example.com/whatever
.
In other words, everything must be redirected to https://www
Here's my .htaccess
:
RewriteCond $1 !^(index\\.php|resources|robots\\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?/$1 [L,QSA]
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I'm using codeigniter 3.11, in config.php
$config['base_url'] = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == "on") ? "https" : "http");
$config['base_url'] .= "://".$_SERVER['HTTP_HOST'];
$config['base_url'] .= str_replace(basename($_SERVER['SCRIPT_NAME']),"",$_SERVER['SCRIPT_NAME']);
Is there any mistake on my .htaccess
?
CodePudding user response:
I've solved redirect to https on TLD (
http://example.com
tohttps://www.example.com
andhttps://example.com
tohttps://example.com
)
(I assume you mean https://www.example.com/
in the last URL. And by "TLD" you really mean the "root directory" (or "document root" or "homepage").)
The only reason this works is that the first rule (the internal rewrite to index.php
- the front-controller) is not triggered when requesting the document root. (index.php
is served by mod_dir instead in this case.)
However, you don't appear to have tested http://www.example.com/
(HTTP www) which would have resulted in a broken redirect to https://www.www.example.com
(doubling the www).
RewriteCond $1 !^(index\\.php|resources|robots\\.txt) RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php?/$1 [L,QSA] RewriteCond %{HTTPS} off RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L] RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Your rules are in completely the wrong order. The canonical redirects need to be before your rewrite to the CI front-controller, otherwise they are simply never processed for requests to non-assets (since the request is routed to index.php
first - the CI front-controller).
However, the canonical redirects themselves are also in the wrong order (and/or incorrect) since a request for http://www.example.com/
(HTTP www) would be erroneously redirected to https://www.www.example.com/
(as already mentioned above).
Aside: You also have erroneous double backslashes in the regex (CondPattern) of the first condition (RewriteCond
directive). This would match a literal backslash - which will never happen, so the first condition is always successful (since it's a negated expression).
Your rules should be something like this instead:
# Canonical redirects
# non-www to www (and HTTPS)
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Front-controller
RewriteCond $1 !^(index\.php|resources|robots\.txt)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [L,QSA]
This assumes you are not implementing HSTS by minimising the number of canonical redirects. (If you do implement HSTS then you need to reverse the two rules - canonical redirects - above as you need to redirect from HTTP to HTTPS on the same host first - which would potentially result in two redirects when requesting HTTP non-www.)
I also modified the HTTP to HTTPS redirect to be consistent with your non-www to www rule, ie. to use the REQUEST_URI
server variable instead of a backreference. For some reason you were using a backreference in one and REQUEST_URI
in the other, with different regex. ^
is more efficient than .*
here as you simply need the rule to be successful, you don't need to actually match anything.