17

I have the following rules on my .htaccess file

# to redirect http to https
RewriteCond %{HTTPS} off
RewriteRule (.*) https://www.example.com/$1 [R=301,L]

# to redirect urls with index.php to /
RewriteCond %{THE_REQUEST} ^.*/index.php 
RewriteRule ^(.*)index.php$ /$1 [R=301,L]

# to redirect non www requests to www url
RewriteCond %{HTTP_HOST} !^www\.example\.com 
RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]

When I am trying to access the website, it turns into a Redirect Loop. How to fix this issue and redirect properly?

Debiprasad
  • 5,895
  • 16
  • 67
  • 95
  • What URL causes the redirect loop? – Jon Lin Aug 20 '13 at 07:23
  • They all work fine for me in a blank htaccess file. Are you sure your https redirect isn't missing the `www`? – Jon Lin Aug 20 '13 at 07:28
  • @JonLin If it's working for you, then it should work for me. But it's not working. Yes, my https redirect is not missing the `www`. It's `RewriteRule (.*) https://www.example.com/$1 [R=301,L]` with the `www`. I guess there might be some issues in the server settings or something else. – Debiprasad Aug 20 '13 at 12:47

6 Answers6

34

Just in case somebody have redirect loop when using Apache http->https rewrite behind load balancer, here's solution that worked for me.

I had the same problem when used RewriteCond %{HTTPS} off for Apache behind load balancer, when load balancer does SSL stuff.

If https version of the site is not configured via Apache ModSSL it doesn't set %{HTTPS} variable to "on" and keeps redirecting infinitely.

The simplest solution to fix it is to target all https traffic to another Apache VirtualHost (when SSL is handled by load balancer) that is the copy of main one, but has different port (lets say 81). And in .htaccess do mod_rewrite for everything that is not on port 81:

ReWriteCond %{SERVER_PORT} !^81$
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R,L]

The second way to do this is to send X-Forwarded-Proto header from load balancer to Apache and use it in rewrite condition:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
Konstantin
  • 18,474
  • 1
  • 14
  • 8
  • 3
    Yay, you're right ! I had the same problem. However I couldn't make your code work, I used this instead : `RewriteEngine On RewriteCond %{SERVER_PORT} 80 RewriteRule ^(.*)$ https://domain.com/$1 [R,L]` – Gabin Apr 02 '14 at 16:25
  • 2
    Thanks Konstantin, been looking for that everywhere. HTTP:X-Forwarded-Proto solved it. – JohnWolf Sep 15 '14 at 22:20
  • Thank you so much! Load balancer was the culprit in my case – Brett Jun 16 '17 at 23:11
16

I've seen a lot of people suffering redirect loops when trying to use .htaccess files to move from http to https. And there are a LOT of different answers to how to solve this issue. Some people say:

ReWriteCond %{SERVER_PORT} 80
OR
RewriteCond %{HTTPS} off
OR
RewriteCond %{HTTPS} !on
OR (as above)
RewriteCond %{HTTP:X-Forwarded-Proto} !https
OR EVEN
RewriteCond %{HTTP:X-Forwarded-SSL} =off

but none of these worked for me. I eventually discovered the underlying truth, that the different servers out there are configured in different ways, and they're all providing different server variables.

If none of the above work for you, then the trick is to use PHP to find out what env variables your particular server is sending you when you access an http page, and what env variables it sends you when you access an https page, and then you can use that variable to do the redirect. Just make a PHP file (such as showphpvars.php) on your server with this code:

<?php phpinfo() ?>

and then view it with a browser. Find the section of variables with _SERVER["HTTP_HOST" (etc)] in it, and have a scout around for one that changes for http versus https. Mine turned out to be a variable called SSL that was set to 1 when using https, and not set at all when using http.

I used that variable to redirect to https with PHP, which is so much nicer than using htaccess, but I think that any of the _SERVER variables can also be accessed using htaccess, if you're keen to continue to use that. Just use the name inside the quotes, without the _SERVER[""] bit that PHP adds.

Z M
  • 161
  • 1
  • 3
  • [@z-m](http://stackoverflow.com/users/4671199/z-m), genuinely useful answer that led me to my individual solution. I can only recommend to have a look at the `phpinfo()` output. It can save you hours of trouble. Kudos! – twigmac Nov 01 '15 at 21:10
  • 1
    Or ENV:HTTPS instead of just HTTPS, as was the case with my redirect loop! – typeoneerror Jul 03 '18 at 18:08
7

For your information, it really depends on your hosting provider. It may be using a Load Balancer, as stated by Konstantin in another answer.

In my case (Infomaniak), nothing above actually worked and I got infinite redirect loop.

The right way to do this is actually explained in their support site:

RewriteEngine on
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://your-domain.com/$1 [R=301,L]

So, always check with your hosting provider. Hopefully they have an article explaining how to do this. Otherwise, just ask the support.

Indigo
  • 745
  • 5
  • 16
  • That worked for Nexcess as well despite of the fact they have `RewriteCond %{HTTPS} off` in their docs https://docs.nexcess.net/article/htaccess-rewrite-commands.html – gorodezkiy Jan 24 '19 at 21:43
  • 1
    Maybe they changed their infrastructure and forgot to update the docs accordingly? You could try to open a ticket to let them know ;-) – Indigo Jan 25 '19 at 07:50
1

If you get a redirect loop no matter what you do in htaccess, do the redirect in PHP instead.

I used phpinfo(), like @z-m suggests, to find the variable that changes when I'm on SSL. In my case it was $_SERVER['HTTP_X_PROTO'] == "https". When not on SSL, this variable is not set.

This is the code I use to redirect from HTTP to HTTPS:

  if ($_SERVER['HTTP_X_PROTO'] != "https") {
    header("HTTP/1.1 301 Moved Permanently");
    $location = "https://" . $_SERVER[HTTP_HOST] . $_SERVER[REQUEST_URI];
    header("Location: $location");
    exit;
  }
Bjarte Aune Olsen
  • 3,230
  • 4
  • 24
  • 36
0
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{
Warfacez
  • 29
  • 2
  • 1
    Although this code may answer the question, providing additional context regarding _why_ and/or _how_ it answers the question would significantly improve its long-term value. Please [edit] your answer to add some explanation. – Toby Speight Jun 20 '16 at 16:56
0

In my case it was:

if ($_SERVER['HTTPS'] != "on")
Rob
  • 26,989
  • 16
  • 82
  • 98
user7590744
  • 167
  • 1
  • 6