Magento HTTPS Redirect Loop

So you’ve enabled HTTPS in your store and suddenly you are faced with a redirect loop. In Magento versions prior to 1.6.2.0, Magento was only capable of checking the Apache $_SERVER['HTTPS'] variable.

In ./lib/Zend/Controller/Request/Http.php the HTTPS sanity check would observe the contents of the HTTPS environment variable, if set to ‘on’ – it would be classed as HTTPS.

return ($this->getServer('HTTPS') == 'on') ? self::SCHEME_HTTPS : self::SCHEME_HTTP;

There are also some other checks within ./app/code/core itself, which include a case insensitive check of ‘on’ or ‘On’. However, when they added the SSL Offload field in 1.6.2.0, they managed to break the flexibility to support varying cases of ‘on/On’. So people are back to hitting redirect loops again.

The best solution

Change your hosting to Sonassi Hosting, seriously, we eat-sleep-breathe Magento and specialise in high performance Magento Hosting. Whether you have got 1,000 visitors a day or 230,000 visitors per day – we have got the right Magento hosting solution for you. Speak to Sonassi Hosting, the Magento Hosting specialists.

The solution (for Apache)

Add this to your ./.htaccess file

############################################
## Case sensitivity fix for Magento 1.6.2.0
SetEnvIf HTTPS On HTTPS=on

The solution (for Nginx, Lighttpd, Varnish or any other reverse proxy to Apache)

Add this to your ./.htaccess file

############################################
## Nginx proxy HTTPS fix for Magento 1.6.2.0
SetEnvIf X-Forwarded-Proto https HTTPS=on

And if you are using Nginx

Open up your virtualhost config for the domain, and within the location handler for the index.php bootstrap, add

location ... {
  fastcgi_param  HTTPS on;
}

The solution (for Nginx, when reverse proxing to Nginx)

If you are SSL unwrapping with another application, Eg. Pound, Stunnel then passing back to Nginx, you’ll need to make Nginx aware of the SSL state using whatever header has been set further up the chain, in our case, we’ve set X_FORWARDED_PROTO

So in your server declaration in Nginx, add some testing logic

server ... {
  set $my_http "http";
  set $my_ssl "off";
  set $my_port "80";

  if ($http_x_forwarded_proto = "https") {
    set $my_http "https";
    set $my_ssl "on";
    set $my_port "443";
  }
}

Then within the location handler, you can dynamically set the HTTPS state

location ... {
  fastcgi_param  HTTPS $my_ssl;
}