Redirecting non-www to www with ninx

May 20, 2018 176 views
Applications Nginx DigitalOcean Getting Started Let's Encrypt Ubuntu 16.04
zub
By:
zub

I am stuck at this point already tried a lot of other articles but none of them is working or might be a silly mistake of mine, guys I need help to redirect my site from non-www to www currently both domains is working, here is what my nignx config looks like:

server {
          server_name myDomain.com;
    return 301 $scheme://www.myDomain.com$request_uri;
}

server {
                listen 80;
        listen [::]:80;
        root /var/www/html;

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

        server_name www.myDomain.com;

        location / {
                        proxy_pass http://localhost:8080;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        }

        # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
        #
        #location ~ \.php$ {
        #       include snippets/fastcgi-php.conf;
        #
        #       # With php7.0-cgi alone:
        #       fastcgi_pass 127.0.0.1:9000;
        #       # With php7.0-fpm:
        #       fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        #}

        # deny access to .htaccess files, if Apache's document root
        # concurs with nginx's one
        #
        #location ~ /\.ht {
        #       deny all;
        #}

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/codeverb.com/fullchain.pem; # managed$
    ssl_certificate_key /etc/letsencrypt/live/codeverb.com/privkey.pem; # manag$
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}


# Virtual Host configuration for example.com
#
# You can move that to a different file under sites-available/ and symlink that
# to sites-enabled/ to enable it.
#
#server {
#       listen 80;
#       listen [::]:80;
#
#       server_name example.com;
#
#       root /var/www/example.com;
#       index index.html;
#
#       location / {
#               try_files $uri $uri/ =404;
#       }
#}

server {
    if ($host = www.myDomain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = myDomain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        listen 80 default_server;
        listen [::]:80 default_server;


    return 404; # managed by Certbot

         }


note: myDomain is my site domain.
Any help is appreciated thanks a lot in advance :)

1 Answer

Hi there,

First, at the top of your configuration file, you have the following server directive:

server {
        server_name myDomain.com;
        return 301 $scheme://www.myDomain.com$request_uri;
}

The reason why it isn't working is that you don't have listen directive. If you take a look at other blocks, you can see that each of them have that directive. It's instructing Nginx on what port to listen for that block, e.g. in you case you probably want both 80 and 443, so you redirect users accessing from both http and https protocols.

However, at the end of your configuration file, you have another server block, which is created by certbot and is doing the same thing. Because of it, you should remove the server block you added at the top of the file.

The server block at the end of configuration files looks like:

server {
        if ($host = www.myDomain.com) {
                return 301 https://$host$request_uri;
        } # managed by Certbot

        if ($host = myDomain.com) {
                return 301 https://$host$request_uri;
        } # managed by Certbot

        listen 80 default_server;
        listen [::]:80 default_server;

        return 404; # managed by Certbot
}

This block is doing almost what you want when you're accessing over http. What you can do is to modify it little bit to include www when your host is myDomain.com (pay attention to highlighted part):

server {
        if ($host = www.myDomain.com) {
                return 301 https://$host$request_uri;
        } # managed by Certbot

        if ($host = myDomain.com) {
                return 301 https://www.$host$request_uri;
        } # managed by Certbot

        listen 80 default_server;
        listen [::]:80 default_server;

        return 404; # managed by Certbot
}

At this point, you have the following redirects:

  • http://www.myDomain.com -> https://www.myDomain.com (redirecting insecure http to secure https; www is already part of the URL).
  • http://myDomain.com -> https://www.myDomain.com (redirect insecure http non-www to secure https with www).

But there's missing one:

  • https://myDomain.com -> https://www.myDomain.com (redirecting secure non-www to www).

This one is tricky, as for server block running on 443, you need to have valid certificates. If you already generated certificates for both non-www and www, you can try using them, in a server block such as:

        server_name myDomain.com;        
        listen 443 ssl; # managed by Certbot
        ssl_certificate /etc/letsencrypt/live/codeverb.com/fullchain.pem; # managed$
        ssl_certificate_key /etc/letsencrypt/live/codeverb.com/privkey.pem; # manag$
        include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
        ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

        return 301 $scheme://www.myDomain.com$request_uri;

Theoretically, something like this could work, but I can't test it to verify it.

The much easier way, but depends on your application, is to allow both non-www and www. Then you don't need redirections and forwards.

Have another answer? Share your knowledge.