Nginx – Redirect loop when forcing SSL on Nginx server

301-redirecthttpsnginxssltls

Lately I have been trying to redirect to HTTPS using Nginx but I keep getting a redirect loop after I try to visit my site in a browser. Here is my full server block config file:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    listen 443 ssl;

    root /var/www;
    index index.php index.html index.htm home.html contact.html projects.html;

    # Make site accessible from http://localhost/
    server_name melone.co;
    return 301  https://$host$request_uri;
    ssl_certificate /path/to/ssl;
    ssl_certificate_key /path/to/ssl;


    location / {
        # First attempt to serve request as file, then
        # as directory, then fall back to displaying a 404.
        try_files $uri $uri/ =404;
        proxy_set_header        X-Forwarded-Proto $scheme;
    }
    error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        root /var/www;
    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(/.+)$;

        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }

}

After searching around I found out that return 301 https://$host$request_uri; would be the easiest way to do this.

So I implemented it into my config file, and ran sudo service nginx restart. I then went to my browser and I got a redirect loop. Once I removed that one line of code, it was gone. So what I think I'm really looking for is a more efficient way to redirect to SSL.

Any help would be appreciated. Thanks

Best Answer

As it stands, you're redirecting all traffic to https, which is good for http traffic, but for https traffic is quite pointless, and results in a redirection loop. What is happening right now is the following: http -> https -> https -> https -> https -> https ... and so on for quite a bit, up until the point where your browser tells you, "it's enough, we won't succeed".

What you want to achieve is redirecting http traffic to https, and process the https traffic (like you did before with the http traffic).

So, you've to split your config into two server directives: One for http (which should do the redirect), the other one for https, which will process the traffic.

Have a look at this example:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;
    server_name melone.co;
    return 301 https://$host$request_uri;
}

Add this server block to your config, remove the corresponding lines in your existing server block, and profit!