Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix http redirects with Nginx?

I have a webpage where http redirects are a bit broken.

The current behavior is this:

www.example.com, example.com, http://www.example.com, http://example.com, https://www.example.com all gets redirected to https://www.example.com

and

https://example.com gets an error saying refused to connect.

I want the behavior to be like this:

example.com, http://example.com, https://example.com redirects to https://example.com

www.example.com, http://www.example.com, https://www.example.com redirects to https://www.example.com

Here is my Nginx config file

server {
       listen 80 default_server;
       listen [::]:80 default_server;
       server_name example.com www.example.com;
       return 301 https://$server_name$request_uri;
}

server {
        add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload";
        listen 443 ssl http2 default_server;
        listen [::]:443 ssl http2 default_server;
        include snippets/ssl-example.com.conf;
        include snippets/ssl-params.conf;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location ~ /.well-known {
                allow all;
        }

        location / {
                try_files $uri $uri/ =404;
        }
}

Reason is because I want these links to work

https://www.ssllabs.com/ssltest/analyze.html?d=example.com

https://www.ssllabs.com/ssltest/analyze.html?d=www.example.com

https://hstspreload.org/?domain=example.com

https://hstspreload.org/?domain=www.example.com

like image 386
user299648 Avatar asked Jan 02 '17 19:01

user299648


Video Answer


2 Answers

You have two independent issues:


  1. Your requests all redirect to example.com, regardless of which specific domain is originally accessed.

This happens because the $server_name variable that you are using is effectively a static variable in a given server context, and has a very distant relationship to $http_host.

The correct way would be to use $host instead (which is basically $http_host with some edge-corner cleanups).


  1. You're receiving connection issues when trying to contact https://example.com, but not https://www.example.com.

There is not enough information in your question to pinpoint the exact origin of this problem.

It can be a DNS issue (A/AAAA records of example.com set at an IP address where appropriate bindings to the https port aren't made).

It could be an issue with the mismatched certificate:

  • Does your certificate cover both example.com and www.example.com? If not, then you can't have both.

  • If you have separate certificates, you may also need to acquire separate IP addresses, or risk preventing a significant number of users from accessing your site due to lack of SNI.


As of note, it should also be pointed out that it is generally a sloppy practice to not have a unified notation on the way your site is accessed. Especially if SEO is of any concern to you, the best practice is to decide on whether you want to go with or without www, and stick to it.

like image 137
cnst Avatar answered Oct 27 '22 04:10

cnst


You need something like this:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name www.example.com;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    add_header Strict-Transport-Security "max-age=300; includeSubdomains; preload";

    return 301 https://www.example.com$request_uri;
}
server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name example.com;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    include snippets/ssl-example.com.conf;
    include snippets/ssl-params.conf;

    add_header Strict-Transport-Security "max-age=300; includeSubdomains; preload";

    location ~ /.well-known {
        allow all;
    }
    location / {
        try_files $uri $uri/ =404;
    }
}

All your requests will be ultimately routed to https://example.com. Your ssl certificate should also be valid for https://www.example.com which I note you have said it is.

like image 41
Dayo Avatar answered Oct 27 '22 03:10

Dayo