skip to Main Content

I am using nginx for managing multiple domains for reverse proxy.

I want to redirect all http request to https

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 301 https://$host$request_uri;
}

However, I am not sure how can I make it work for rewriting non www requests to redirect to www in generic way excluding rewriting those requests that already has www in requests as if I just modify below rule it creates problem when someone write as www.domain.com it
rewrite to www.www.domain.com

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

Please check this image to understand the issue.
redirecting to www.www.domain

So I need to have some condition that handles that.

3

Answers


  1. Please try this

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

    this will rewrite all 3 domains to https://yourdomain.com

    I am not sure about my answer. I am not able to test this now.
    please try this and comment back

    Login or Signup to reply.
  2. If you want a generic approach, you can use map directive (should be placed outside the server block):

    map $host $basename {
        ~^www.(.+)  $1;
        default      $host;
    }
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        return 301 https://$basename$request_uri;
    }
    

    Update 1

    It’s look I misread your question (you need to redirect example.com to www.example.com but my answer does an opposite thing), please try the following:

    map $host $basename {
        ~^www.(.+)  $host;
        default      www.$host;
    }
    server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        return 301 https://$basename$request_uri;
    }
    

    Update 2

    OP asks an additional question:

    Is there a way to exclude specific sub domain like static.example.com which I don’t want to rewrite to www.static.example.com?

    Yes, rewrite of static subdomain can be prevented with the following map block:

    map $host $basename {
        ~^(?:www|static)..+  $host;
        default               www.$host;
    }
    

    If you want to prevent rewrite of any three-component domain name, you can use

    map $host $basename {
        ~[^.]+.[^.]+.[^.]+  $host;
        default               www.$host;
    }
    
    Login or Signup to reply.
  3. Non-www to www & https redirect

    If I understand correctly, then you want to force non www to www. And you want to force all requests to https. This config code checks if the $host start with "www." or not. If it does not, then nginx will add "www." before the $host then return the correct https location. It will work with subdomains as well.

    server {
      if ($host !~* ^www.) {
        # if host name starts with (case insensitive) "www."
        return 301 https://www.$host$request_uri;
      }
      if ($host ~* ^www. ) {
        # if host name doesn't start with (case insensitive) "www."
        return 301 https://$host$request_uri;
      }
      listen 80 default_server;
      listen [::]:80 default_server;
      server_name _;
      return 404;
    }
    

    Possibly better way with Certbot

    You can automatically produce the code you need by using Certbot. It will also help you manage certificates a lot and automate renewal. But Certbot will not change non-www to www, you’ll have to edit auto-generated config to look like the config above. The other difference is that you will be expected to have different config blocks/files per domain, but not sure if necessary. This is what the default config looks like per domain.

    server {
      if ($host = www.yourdomain.com) {
        return 301 https://$host$request_uri;
      } # managed by Certbot
    
    
      if ($host = yourdomain.com) {
        return 301 https://$host$request_uri;
      } # managed by Certbot
    
    
      listen 80;
      listen [::]:80;
      server_name yourdomain.com www.yourdomain.com;
      return 404; # managed by Certbot
    }
    

    I think it’s best practice to separate the config files for each domain and subdomain and use the default Certbot format until you have understood Nginx more. This way you can disable the redirect of non-www to www very easily. The default code above from Certbot, would be what you would put when you don’t want to redirect in that case. Long term this makes more sense to me, but I understand when users are more comfortable with www or other parts of the website might need the www.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search