Redirect loop when forcing HTTPS

21,014

Solution 1

Thanks to HBruijn's comment, I understood why I was getting the redirect loop.

The traffic from the ELB will always be HTTP as it handles the HTTPS traffic to the user but to the server it's HTTP, so my previous rule will result in a loop.

After some research I found that the load balancer forwards a few userful headers like X-Forwarded-Proto. This can be used to determine if the client is using HTTP or HTTPS like so:

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

I hope the above helps someone else when trying to force HTTPS behind Amazon Web Services Load balancer.

Solution 2

Rather than doing so in a .htaccess file, simply set the SSL Redirect in the non-SSL VirtualHost entry of your Apache configuration:

NameVirtualHost *:80
<VirtualHost *:80>
   ServerName www.example.com
   Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost _default_:443>
   ServerName www.example.com
   DocumentRoot /usr/local/apache2/htdocs
   SSLEngine On
# etc...
</VirtualHost>

which is much more efficient.

Additionally: my pet peeve, quoted from from the manual on .htaccess files:

You should avoid using .htaccess files completely if you have access to httpd main server config file. Using .htaccess files slows down your Apache http server. Any directive that you can include in a .htaccess file is better set in a Directory block in the main Apache configuration file(s), as it will have the same effect with better performance.

Share:
21,014

Related videos on Youtube

Abs
Author by

Abs

Updated on September 18, 2022

Comments

  • Abs
    Abs over 1 year

    I am using the following to force HTTPS on my main website.

    ### Force SSL
    RewriteCond %{HTTPS} !=on
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    

    If you want to view the full htaccess file, I have placed it below:

    <IfModule mod_rewrite.c>
    
        RewriteEngine On
        RewriteBase /
    
        ### Blacklist via Referrers
    
        RewriteCond %{HTTP_REFERER} removed\.net [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.net [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.sx [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.com [NC,OR]
        RewriteCond %{HTTP_REFERER} removed\.org [NC]
        RewriteRule ^(.*)$ - [F,L]
    
        ### Force SSL
        #RewriteCond %{HTTPS} !=on
        #RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
    
        ### Canonicalize codeigniter URLs
    
        # If your default controller is something other than
        # "welcome" you should probably change this
        RewriteRule ^(welcome(/index)?|index(\.php)?)/?$ / [L,R=301]
        RewriteRule ^(.*)/index/?$ $1 [L,R=301]
    
        # Removes trailing slashes (prevents SEO duplicate content issues)
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.+)/$ $1 [L,R=301]
    
        # Enforce NO www
        RewriteCond %{HTTP_HOST} ^www [NC]
        RewriteRule ^(.*)$ https://removed.com/$1 [L,R=301]
    
        # Removes access to the system folder by users.
        # Additionally this will allow you to create a System.php controller,
        # previously this would not have been possible.
        # 'system' can be replaced if you have renamed your system folder.
        RewriteCond %{REQUEST_URI} ^system.*
        RewriteRule ^(.*)$ /index.php/$1 [L]
    
        # Checks to see if the user is attempting to access a valid file,
        # such as an image or css document, if this isn't true it sends the
        # request to index.php
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ index.php/$1 [L]
    
    </IfModule>
    
    <IfModule !mod_rewrite.c>
    
        # Without mod_rewrite, route 404's to the front controller
        ErrorDocument 404 /index.php
    
    </IfModule>
    

    I am struggling to figure how the redirect loop is happening.

    Update

    I did not make it clear that my web server (Apache) is only configured with one virtual host on port 80 that gets HTTP and HTTPS traffic directed to it by the load balancer. The load balancer handles the SSL connection.

  • Abs
    Abs about 9 years
    Does the above solution mean all pages that are not SSL will redirect to the homepage? That is not ideal to be honest. We use htaccess files as it's easier for deployments to multiple environments as we swap htaccess files for each environment.
  • HBruijn
    HBruijn about 9 years
    I included the link so you could Read The Fine Manual and you would have seen that http://www.example.com/something?else=true will be redirected to https://www.example.com/something?else=true and NOT to the homepage. - With regards to .htaccess all I'm going to say is: to many people use them and continue to copy them without actually understanding either their use-case or their impact.
  • Abs
    Abs about 9 years
    The above solution won't work for us as we make use of the AWS ELB that routes SSL traffic to our Apache server that is only configured for port 80. It results in a redirect loop when I put the above statement in our config file as both HTTP and HTTPS hit the same virtual host. Any idea why our htaccess results in a redirect loop?
  • Tania Rascia
    Tania Rascia over 8 years
    Thank you! This was the only one that didn't cause a rewrite loop for me.
  • Gruber
    Gruber about 8 years
    Same thing for me on CloudFlare using the given HTML5BP .htacess file enabling the rule to force https
  • Josh Woodcock
    Josh Woodcock over 7 years
    Oh my gosh. I can't believe that AWS was screwing me up. I couldn't figure out why every single example didn't work until I came across this answer. Thanks!