Timur Gafforov Timur Gafforov - 3 years ago 83
HTTP Question

http to https redirection through htaccess: incorrect redirection error

I need all http to redirect https:

RewriteEngine On
RewriteBase /

RewriteCond %{HTTP_HOST} !^some-domain\.com$ [NC]
RewriteRule ^(.*)$ https://some-domain.com/$1 [R=301,L]

RewriteCond %{THE_REQUEST} /(\.+) [OR]
RewriteCond %{THE_REQUEST} /(\?+) [OR]
RewriteCond %{THE_REQUEST} /(/+)
RewriteRule ^(.*)$ 404.html [L]
RewriteRule ^core/(install|temp|smarty|modules|languages|includes|functions|fonts|files|config|classes|cache|backup|tpl)/(.*) - [F]
RewriteRule ^data/(.+)\.(tpl\.html|php|php3|php4|php5|phtml|pl|cgi) - [F]
RewriteRule ^install_check\.html$ install.php?check=yes [L]
RewriteRule ^index\.html$ index.php [L]
RewriteRule ^news\.html$ index.php?news=yes [L]
RewriteRule ^price\.html$ index.php?show_price=yes [L]
RewriteRule ^cart\.html$ index.php?shopping_cart=yes [L]
RewriteRule ^wide_search\.html$ index.php?search_with_change_category_ability=yes [L]
RewriteRule ^feedback\.html$ index.php?feedback=yes [L]
RewriteRule ^compare\.html$ index.php?comparison_products=yes [L]
RewriteRule ^page_([0-9]+)\.html$ index.php?show_aux_page=$1 [L]
RewriteRule ^product_([0-9]+)\.html$ index.php?productID=$1 [L]
RewriteRule ^category_([0-9]+)\.html$ index.php?categoryID=$1 [L]
RewriteRule ^category_([0-9]+)_offset_([0-9]+)\.html$ index.php?categoryID=$1&offset=$2 [L]
RewriteRule ^category_([0-9]+)_show_all\.html$ index.php?categoryID=$1&show_all=yes [L]
RewriteRule ^show_news_([0-9]+)\.html$ index.php?fullnews=$1 [L]

# BEGIN Articles
RewriteRule ^poleznoe/([^/]+)\.html$ index.php?fullarticles=$1 [L]
RewriteRule ^poleznoe/([0-9]+)/$ index.php?articles=yes&offset=$1 [L]
RewriteRule ^poleznoe/$ index.php?articles=yes [L]
# END Articles

RewriteRule ^google([a-z0-9_-]+).html$ google$1.html [L]
RewriteRule ^yandex([a-z0-9_-]+).html$ yandex$1.html [L]

# BEGIN Human friendly URL's
RewriteRule ^news/([^/]*).html$ index.php?uri=$1&uriFor=news [L]
RewriteRule ^([^/]*).html$ index.php?uri=$1&uriFor=pages [L]
RewriteRule ^([^/]*)/$ index.php?uri=$1&uriFor=category [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !([^/]*)/$
RewriteRule ^([^/]*)$ $1/ [L,R=301]
RewriteRule ^(([^/]*)_offset_([0-9]+))/$ index.php?uri=$1&uriFor=category&offset=$2 [L]
RewriteRule ^([^/]*)_show_all/$ index.php?uri=$1&uriFor=category&show_all=yes [L]
#RewriteRule ^([^/]*)/([^/]*)/([^/]*)\.html$ index.php?uri=$3&uriFor=product [L]
RewriteRule ^([^/]*)/([^/]*)\.html$ index.php?uri=$2&uriFor=product [L]
# END Human friendly URL's

I've googled and came accross this solution several times:

RewriteCond %{HTTPS} off
RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

but if I place it after
RewriteEngine On
or after
RewriteBase /
or anywhere near or between

RewriteCond %{HTTP_HOST} !^some-domain\.com$ [NC]
RewriteRule ^(.*)$ https://some-domain.com/$1 [R=301,L]

It gives me incorrect redirection error when I load the page. Please, tell me what I am doing wrong.

Thanks in advance.

Answer Source

$_SERVER['HTTPS'] is always empty, but $_SERVER['HTTP_X_FORWARDED_PROTO'] returns https when I am on https page

This tells you that your SSL is managed by a front-end proxy server, not your application server. Your application server does not appear to have an SSL cert installed and is most probably serving a plain HTTP request over port 80 to the proxy server. The proxy server then serves a secure HTTPS response back to the client, so the clients request is secure.

What this means is that if your application server attempts to redirect HTTP to HTTPS by simply checking the standard server variables (ie. HTTPS or SERVER_PORT) then this is likely to fail with a redirect loop since HTTPS is always off and SERVER_PORT is always 80 - even after the redirect. (Note that the HTTPS Apache variable is likely to be "off", but this often translates to a PHP superglobal $_SERVER['HTTPS'] that is empty - that's just how PHP handles it.)

Note that the HTTP to HTTPS redirect could be performed in the front-end proxy instead, before it even gets to the application server. (Cloudflare does this with its page rules.)

Alternatively, you can examine the additional HTTP request headers that are set by the proxy server as the request is forwarded from the proxy to your application server. The X-Forwarded-Proto header (which is stored by PHP as $_SERVER['HTTP_X_FORWARDED_PROTO']) is set by the proxy server and tells you what protocol the client used to connect to your proxy.

So, bringing the canonical redirects together:

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

# http to https redirect
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

With the format of the directives you posted, the www to non-www redirect should come first in order to avoid a double redirect when requesting http://www.example.com (ie. HTTP and www).

Note that you should only use this type of HTTP to HTTPS redirect when you are behind a proxy server that is handling the SSL. Otherwise, the X-Forwarded-Proto HTTP request header could be faked by a malicious client request (this, however, should be handled by your proxy server).

These two rules can be combined into 1 rule if you wish:

# Canonical redirect (no-www and HTTPS)
RewriteCond %{HTTP_HOST} !^example\.com [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule (.*) https://example.com/$1 [R=301,L]
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download