Correctly switching between HTTP and HTTPS using .htaccess

75,881

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.

Share:
75,881

Related videos on Youtube

Alistair Holt
Author by

Alistair Holt

Updated on July 09, 2022

Comments

  • Alistair Holt
    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
      random almost 15 years
      Does it have to be with htaccess? What language is the site using?
    • Chris Wesseling
      Chris Wesseling over 12 years
      What are you trying to prevent with the https?
  • Curtis Tasker
    Curtis Tasker almost 15 years
    I checked the code on my server, using both blocks listed above, and it works fine with no redirect loops.
  • Luke Stevenson
    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
    antitoxic almost 12 years
    @wilmoore's suggestion to use %{SERVER_NAME} addition will be useful
  • Juhani
    Juhani over 11 years
    Your 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
    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
    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
    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
    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
    gregn3 about 8 years
    I had to use this check to get it to work RewriteCond %{HTTP:X-Forwarded-Proto} !https
  • Malachi
    Malachi about 7 years
    Probably better/safer to use "RewriteCond %{HTTPS} off" than "RewriteCond %{SERVER_PORT} ^80$"....(as in the other answer)
  • Wil Moore III
    Wil Moore III about 7 years
    @Malachi You are probably correct; however, I can't verify it at this time.
  • Džuris
    Džuris about 7 years
    Does 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.