Correctly switching between HTTP and HTTPS using .htaccess
Solution 1
I use something similar to this for my admin folder in wordpress:
#redirect all https traffic to http, unless it is pointed at /checkout
RewriteCond %{HTTPS} on
RewriteCond %{REQUEST_URI} !^/checkout/?.*$
RewriteRule ^(.*)$ http://mydomain.com/$1 [R=301,L]
The RewriteCond %{HTTPS} on
portion may not work for all web servers. My webhost requires RewriteCond %{HTTP:X-Forwarded-SSL} on
, for instance.
If you want to force the reverse, try:
#redirect all http traffic to https, if it is pointed at /checkout
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} ^/checkout/?.*$
RewriteRule ^(.*)$ https://mydomain.com/$1 [R=301,L]
If you want some alternate ways to do it, check out askapache.
Solution 2
This should work in pretty much every scenario and should work in your actual vhost or .htaccess:
RewriteEngine on
RewriteCond %{SERVER_PORT} ^80$
RewriteRule ^(.*)$ https://%{SERVER_NAME}/%{REQUEST_URI} [R=301,L]
(do not forget the slash before %{REQUEST_URI} as this may allow passing a portnumber, which is dangerous)
Solution 3
RewriteEngine on
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{SERVER_NAME}/%{REQUEST_URI} [R=301,L]
I had some problem being behind a loadballancer. This how i fixed it.
Solution 4
As detailed in this answer, fix your application to use https://
links when needed. Don't rely on automatic redirections, this could lead you to a false sense of security if you haven't made your links/forms served over https://
go to https://
URLs too. Using mod_rewrite
automatically makes it harder to detect such mistakes (which can also be vulnerabilities).
Solution 5
For me worked this (I used it for wordpress site and redirecting to HTTPS). You have to add the condition and rule lines just behind RewriteEngine and RewriteBase lines:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# I added these two lines for redirect to HTTPS
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://www.yoursite.com/$1 [R=301,L]
# (end of custom modifications)
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress`
Have a look to condition RewriteCond %{HTTP:X-Forwarded-Proto} !https
- only this worked for my server hosting.
(I tried RewriteCond %{SERVER_PORT} !^443$
or RewriteCond %{HTTPS} off
as well, but without success.
Related videos on Youtube
Alistair Holt
Updated on July 09, 2022Comments
-
Alistair Holt almost 2 years
We've got a shopping site which we're hosting on a shared host (Mediatemple Gridserver). Some parts of the site need to use HTTPS (checkout etc) but the rest should be using HTTP.
Does anyone know how we can always force the correct use of HTTP/HTTPS for particular URLs? We've had it working in various states but we can't get a request for a page that should be on HTTP but is requested with HTTPS to switch back correctly.
I've had a look around SO but couldn't find a suitable answer to this.
-
random almost 15 yearsDoes it have to be with htaccess? What language is the site using?
-
Chris Wesseling over 12 yearsWhat are you trying to prevent with the https?
-
-
Curtis Tasker almost 15 yearsI checked the code on my server, using both blocks listed above, and it works fine with no redirect loops.
-
Luke Stevenson over 12 years+1. Great answer. The
RewriteCond %{HTTP:X-Forwarded-SSL} on
was needed in my case because I am using RackSpace's cloud sites. -
antitoxic almost 12 years@wilmoore's suggestion to use
%{SERVER_NAME}
addition will be useful -
Juhani over 11 yearsYour answer, while elegant, has a small mistake. The last line should have a slash (/) after SERVER_NAME, or www.test.com/dir forwards to test.comdir
-
Wil Moore III over 11 years@Juhani Thanks for your comment. Actually, %1 maps to the {REQUEST_URI} environment variable which is root relative. In other words, if you requested example.com/123, then REQUEST_URI === '/123'; thus, another slash would be superfluous. It would still work because in most modern configurations, apache will strip off the extra slash. Unless you like having apache do more work, you don't need the slash. That being said, I did update my original answer to use %{REQUEST_URI} instead of %1 as it is more intention revealing.
-
outis about 11 years@wilmoore: that's correct when the options are placed in the server configuration file, as the rewrite engine can hook URL-to-filename-translation. However, when placed in a per-directory configuration file, the URI has already been mapped to a pathname by the time the rewrite engine steps in. The rewrite engine handles this by stripping the directory prefix, which ends up removing the leading '/', and matching against the result.
-
outis about 11 years@wilmoore: it was actually fine without the "/" before the "%{REQUEST_URI}", which holds the original request URI and isn't updated by the rewrite engine. I was trying to point out that "$1" wouldn't be correct in a per-directory context for the reason stated by Juhani. Thus your first change didn't just make the intent clearer, it corrected the error Juhani mentioned. Without "%{REQUEST_URI}", you'd have to use
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R=301,L]
. Sorry my comment caused some confusion. -
Wil Moore III about 11 years@outis, thanks...I haven't had to deal with an Apache server for quite a while so I wasn't able to test. Thanks for the reassurance.
-
gregn3 about 8 yearsI had to use this check to get it to work
RewriteCond %{HTTP:X-Forwarded-Proto} !https
-
Malachi about 7 yearsProbably better/safer to use "RewriteCond %{HTTPS} off" than "RewriteCond %{SERVER_PORT} ^80$"....(as in the other answer)
-
Wil Moore III about 7 years@Malachi You are probably correct; however, I can't verify it at this time.
-
Džuris about 7 yearsDoes that actually work? It threw me into a redirect loop. If you have loadbalancer, the HTTPS will not be set and the first RewriteCond will be met. If you don't, the second RewriteCond will be met. Thus every time you will get redirected again. I got it working using (another answer)[stackoverflow.com/a/26623196/2182900] that is basically the same thing but without the
[OR]
- you only redirect if both HTTPS is off and the HTTP:X-Forwarded-Proto is not https.