Tutorial

How To Redirect www to Non-www with Nginx on Ubuntu 14.04

Updated on December 16, 2022
How To Redirect www to Non-www with Nginx on Ubuntu 14.04
Not using Ubuntu 14.04?Choose a different version or distribution.
Ubuntu 14.04

Introduction

Many web developers need to allow their users to access their website or application via both the www subdomain and the root (non-www) domain. That is, users should have the same experience when visiting www.my-website.com and my-website.com. While there are many ways to set this up, the most SEO-friendly solution is to choose which domain you prefer—the subdomain or the root domain—and have the web server redirect users who visit the other one to the preferred domain.

There are many kinds of HTTP redirects, but in this scenario, it’s best to use a 301 redirect, which tells clients, “The website you have requested has permanently moved to another URL. Go there instead.” Once the browser receives the HTTP 301 response code from the server, it sends a second request to the new URL given by the server and the user is presented with the website, probably never noticing they were redirected.

Why not configure your web server to just serve the same website for requests to both domain names? That may seem easier, but it does not confer the SEO advantages of the 301 redirect. A permanent redirect tells search engine crawlers that there is one canonical location for your website, and this improves the search rankings of that one URL.

In this tutorial, you will configure a 301 redirect using Nginx on Ubuntu 14.04. If you are running Apache instead of Nginx, see this tutorial instead: How To Redirect www to Non-www with Apache on Ubuntu 14.04 .

Prerequisites

To complete this tutorial, you first need:

Let’s get started by configuring your DNS records.

Step 1 — Configuring DNS Records

First, you need to point both www.my-website.com and my-website.com to your server running Nginx. (The rest of the tutorial assumes your domain is my-website.com. Replace that with your own domain wherever you see it below.) You will do this by creating a DNS A record for each name that points to your Nginx server’s IP address.

Open your DNS provider’s web console. This tutorial uses DigitalOcean DNS.

In the Add a domain form, enter your registered domain name in the text field and click Add Domain. This will bring up the new domain’s page, where you can view, add, and delete records for the domain.

Under Create new record, type “@” in the HOSTNAME text field. This is a special character that indicates you are adding a record for the root domain name, a record for just plain my-website.com. In the WILL DIRECT TO text field, enter the public IPv4 address of your server, and click Create Record. (No need to change the TTL.)

For your second DNS record, you could use a CNAME record instead of an A record. A CNAME record is an alias that points to another name instead of an IP address. You could create a CNAME that directs www.my-website.com to my-website.com, and any HTTP request for the www subdomain would find its way to your server since you just created the A record for the root domain. But to keep things simple, just create another A record like the first one, entering “www” in the HOSTNAME field and the server’s public IP address in the WILL DIRECT TO field.

When you have created both records, it should look something like this:

Required A records

With the two records in place, web requests for both my-website.com and www.my-website.com should reach your Nginx server. Now let’s configure the server.

Step 2 — Configuring the Redirect in Nginx

As stated in the Prerequisites, you should already have your website configured in Nginx. It does not matter whether the site’s server block appears in the main /etc/nginx/sites-enabled/default file or in its own file. The important thing is that you have some server block configured with the server_name directive set to my-website.com and/or www.my-website.com. Whether your server_name contains one or both names, now is the time to decide which name you would like to be the one and only name to host the site.

Open the file that contains your website configuration (e.g., /etc/nginx/sites-available/my-website.com.conf) in nano or your favorite editor and find the server_name directive:

  1. sudo nano /etc/nginx/sites-available/my-website.com.conf
/etc/nginx/sites-available/my-website.com.conf
server {
    . . .
    server_name my-website.com www.my-website.com
    . . .
}

If you want to redirect www.my-website.com to my-website.com, remove www.my-website.com from the server_name line, and save and exit the file. (If you want to redirect my-website.com to www.my-website.com, remove my-website.com instead.)

Then, create a new Nginx configuration file called /etc/nginx/sites-available/www.my-website.com.conf (or /etc/nginx/sites-available/my-website.com.conf, if that is the name you are redirecting). Name the file whatever you like, but as with all Nginx configuration files, the file name must end in .conf:

  1. sudo nano /etc/nginx/sites-available/www.my-website.com.conf

Add the following server block to the file, replacing my-website.com with your own domain name:

/etc/nginx/sites-available/www.my-website.com.conf
server {
    server_name www.my-website.com;
    return 301 $scheme://my-website.com$request_uri;
}

If you are redirecting my-website.com to the www subdomain instead, put my-website.com only in the server_name, and www.my-website.com in the URL on the next line.

Save and exit when you are finished. Then make a symlink in /etc/nginx/sites-enabled to this new file so Nginx will pick it up after restarting:

  1. sudo ln -s /etc/nginx/sites-available/www.my-website.com.conf /etc/nginx/sites-enabled/

This configures Nginx to send a 301 redirect back to any clients requesting www.my-website.com, and directs them to visit my-website.com instead. The redirect preserves the request URI, so that a request to http://www.my-website.com/login.php will be redirected to http://my-website.com/login.php.

Note: The server block above does not contain the listen directive. This is OK, because as mentioned in this tutorial, any server block without a listen directive will listen on 0.0.0.0:80 (port 80 on all interfaces). But if your Nginx server is home to multiple IP addresses, or if your site listens on a port other than 80, you may need to add a listen directive to spell out the specific IP address and port. Use the same value for listen that your site’s main server block uses.

Before applying the changes, check that your Nginx configuration is error free:

  1. sudo nginx -t

Unless you made a syntax error (e.g., you forgot a semicolon), the configuration should be OK.

Output
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful

Now restart Nginx to apply the new redirect rule:

  1. sudo service nginx restart

Before visiting www.my-website.com in your browser, make a request using curl on either your server or your local machine (if curl is installed locally):

  1. curl -IL http://www.my-website.com

The -I flag tells curl to show only the headers from the server response. The -L flag tells curl to obey any redirects from the server by automatically making a second request, this time to the URL given in the Location header (just as a web browser would do). Since you have configured the 301 redirect, curl should make two requests, and you should see just the headers of the two responses:

Output
HTTP/1.1 301 Moved Permanently Server: nginx/1.20.1 Date: Thu, 08 Dec 2022 19:24:44 GMT Content-Type: text/html Content-Length: 169 Connection: keep-alive Location: http://my-website.com HTTP/1.1 200 OK Server: nginx/1.20.1 Date: Thu, 08 Dec 2022 19:24:44 GMT Content-Type: text/html Content-Length: 57 Last-Modified: Thu, 01 Dec 2022 22:10:57 GMT Connection: keep-alive ETag: "63892671-39" Accept-Ranges: bytes

In the 301 (Moved Permanently) response to the original request to http://www.my-website.com, notice the last header: Location: http://my-website.com. The second response is from curl’s followup request to http://my-website.com, and if your website is healthy, the server should have responded with 200 (OK).

Finally, visit http://www.my-website.com in your web browser. Blink, and you’ll miss the redirect. Your website should appear as usual, but look again in your address bar and notice that the “www” is missing from the URL. Most users will never notice this, and so they will have the same experience as if they had requested http://my-website.com.

Conclusion

In this tutorial, you added two DNS records for your website and configured Nginx to redirect a secondary domain to your preferred domain. Now your website is reachable via both domains. Maybe it already was before you read this tutorial; perhaps you were serving it directly from both domain names. But with just four more lines of Nginx configuration, you have improved your website’s standing in the eyes of the search engines—and thereby exposed it to more users across the internet.

Want some further reading on how Nginx decides which server block will handle a given request? Check out this guide: Understanding Nginx Server and Location Block Selection Algorithms.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors

Default avatar

Technical Writer at DigitalOcean


Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
10 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

You should use:

server {
  server_name www.domain.com;
  return 301 $scheme://domain.com$request_uri;
}
server {
  server_name domain.com;
  [...]
}

Otherwise you will get HTTP/1.1 301 Moved Permanently for the www and non-www versions.

Using the code above you’ll get HTTP/1.1 200 OK for the non-www domain. See: http://wiki.nginx.org/Pitfalls#Server_Name

How do I go it on config with SSL ? Should I create 3 server blocks ?

Every form of www to non-www redirects works fine except https://www.example.com. When I run curl -I https://www.example.com I get HTTP/1.1 302 Found and no redirects!

This is really helpful!

Great tutorial!

But doesn’t a simple

Record Type Source Target
A domain.com ip_address
CNAME www.domain.com domain.com

do the trick?

It didn’t work for me. I researched and fixed with this way. Open /etc/nginx/sites-available/example . And edit the file like that:

server {
    # SERVER NAME WITH WWW
    server_name www.example.com;

    # LOCATION CONFIGURATIONS
    location = /favicon.ico { ... }
    location /.../ {
        root ...
    }
    location /.../ {
        root ...
    }

    location / {
        ...
    }


    # CERTBOT CONFIGURATIONS FOR SSL
    listen 443 ssl;
    ssl_certificate ... # managed by Certbot
    ssl_certificate_key ... # managed by Certbot
    include ... # managed by Certbot
    ssl_dhparam ... # managed by Certbot

}

server {
    # SERVER NAME WITHOUT WWW
    server_name example.com;

    # CERTBOT CONFIGURATIONS AGAIN
    listen 443 ssl;
    ssl_certificate ... # managed by Certbot
    ssl_certificate_key ... # managed by Certbot
    include ... # managed by Certbot
    ssl_dhparam ... # managed by Certbot

    # REDIRCET TO WWW
    return 301 https://www.example.com$request_uri;

}

I use like:

upstream my_project_server {
  # fail_timeout=0 means we always retry an upstream even if it failed
  # to return a good HTTP response (in case the Unicorn master nukes a
  # single worker for timing out).

  server unix:/webapps/my_project/run/gunicorn.sock fail_timeout=0;
}

server {
  server_name domain.com www.domain.com;

    if ($host = www.domain.com) {
        return 301 $scheme://domain.com$request_uri;
    }

    client_max_body_size 4G;

    access_log /webapps/my_project/logs/nginx-access.log;
    error_log /webapps/my_project/logs/nginx-error.log;
 
    location /static/ {
        alias   /webapps/my_project/static_in_env/static_root/;
    }
    
    location /media/ {
        alias   /webapps/my_project/static_in_env/media_root/;
    }

    location / {
        # an HTTP header important enough to have its own Wikipedia entry:
        #   http://en.wikipedia.org/wiki/X-Forwarded-For
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

        # enable this if and only if you use HTTPS, this helps Rack
        # set the proper protocol for doing redirects:
        # proxy_set_header X-Forwarded-Proto https;

        # pass the Host: header from the client right along so redirects
        # can be set properly within the Rack application
        proxy_set_header Host $http_host;

        # we don't want nginx trying to do something clever with
        # redirects, we set the Host: header above already.
        proxy_redirect off;

        # set "proxy_buffering off" *only* for Rainbows! when doing
        # Comet/long-poll stuff.  It's also safe to set if you're
        # using only serving fast clients with Unicorn + nginx.
        # Otherwise you _want_ nginx to buffer responses to slow
        # clients, really.
        # proxy_buffering off;

        # Try to serve static files from nginx, no point in making an
        # *application* server like Unicorn/Rainbows! serve static files.
        if (!-f $request_filename) {
            proxy_pass http://my_project_server;
            break;
        }
    }

    # Error pages
    error_page 500 502 503 504 /500.html;
    location = /500.html {
        root /webapps/my_project/static/;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

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


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



    listen   80;
    server_name domain.com www.domain.com;
    return 404; # managed by Certbot
}

Hello, i`m very new to this, could you please tell me how to save after putting:

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

Thank you

Thanks, it is now working properly for my site.

Hmm, it didn’t work for me. I arrive to the “Welcome to nginx” page when browsing to “myotherdomain.com

server {
    server_name www.myotherdomain.com;
    return 301 $scheme://test.domain.com$request_uri;
}
server {
        listen 80 default_server;
        listen [::]:80 default_server ipv6only=on;
        listen 443 ssl http2 default_server;
        listen [::]:443 ssl http2 default_server;

        root /var/www/html;
        index index.php index.html index.htm;

        #Password protects the test subdomain
        auth_basic "Restricted Content";
        auth_basic_user_file /etc/nginx/.htpasswd;
        # Make site accessible from https://test.domain.com/
        server_name test.domain.com;
        include snippets/ssl-test.domain.com.conf;
        include snippets/ssl-params.conf;
        location ~ /.well-known {
                allow all;
        }
        location / {
                try_files $uri $uri/ /index.php$is_args$query_string;
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
                root /usr/share/nginx/html;
        }
        location ~ [^/]\.php(/|$) {
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        if (!-f $document_root$fastcgi_script_name) {
        return 404;
        }
        # Mitigate https://httpoxy.org/ vulnerabilities
        fastcgi_param HTTP_PROXY "";
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        include fastcgi_params;
        }
        location ~ \.php$ {
        #match actual filename with extension or file not found
        #try_files $uri $uri =404;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        }
}

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Featured on Community

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more