// Tutorial //

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

Published on May 4, 2015
Default avatar
By Mitchell Anicas
Developer and author at DigitalOcean.
How To Redirect www to Non-www with Nginx on Ubuntu 14.04

Introduction

When you have your web site or application up and running behind a domain, it is often desirable to also allow your users access to it via the plain domain name and the www subdomain. That is, they should be able to visit your domain with or without the “www.” prefix, e.g. example.com or www.example.com, in a web browser, and be presented with the same content. While there are a variety of ways to set this up, the best solution, for consistency and SEO considerations, is to choose which domain you prefer, plain or www, and redirect the other one to the preferred domain. This type of redirect is called a Permanent Redirect, or “301 redirect”, and can be easily set up by properly configuring your DNS resource records and web server software.

This tutorial will show you how to redirect a www URL to non-www, e.g. www.example.com to example.com, with Nginx on Ubuntu 14.04. We will also show you how to redirect in the other direction, from a non-www URL to www. The CentOS 7 version of this tutorial is available here.

If you want to perform this type of redirect with Apache as your web server, you should follow this tutorial instead: How to Redirect www to non-www with Apache on Ubuntu 14.04.

Prerequisites

This tutorial assumes that you have superuser privileges, i.e. sudo or root, on the server that is running Nginx. If you don’t already have that set up, follow this tutorial: Initial Server Setup on Ubuntu 14.04.

It is assumed that you have Nginx installed. If you do not already have this set up, there are several tutorials on the subject under the Nginx tag.

You must be able to add records to the DNS that is managing your domain. If you do not already have a domain, you may purchase one from a domain registrar, and manage it with the registrar’s DNS or DigitalOcean’s DNS. In this tutorial, we will use the DigitalOcean DNS to create the necessary records.

Let’s get started by configuring your DNS records.

Configure DNS Records

In order to set up the desired redirect, www.example.com to example.com or vice versa, you must have an A record for each name.

Open whatever you use to manage your DNS. For our example, we’ll use the DigitalOcean DNS.

If a domain (also known as a zone) record does not already exist, create one now. The hostname should be your domain, e.g. example.com, and the IP address should be set to the public IP address of your Nginx server. This will automatically create an A record that points your domain to the IP address that you specified. If you are using another system to manage your domain, you may need to add this manually.

Next, add another A record with “www” as the hostname (or “www.example.com” if the partial subdomain doesn’t work), and specify the same IP address.

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

Required A records

Note: This will also work with CNAME records, as long as the canonical name’s A record refers to the IP address of your Nginx web server.

Now your server should be accessible via the www and non-www domain, but we still need to set up the redirect. We’ll do that now.

Configure Nginx Redirect

In order to perform the 301 redirect, you must add a new Nginx server block that points to your original server block.

Open your Nginx server block configuration in an editor. We’ll use the default configuration file, /etc/nginx/sites-enabled/default, in our example:

sudo vi /etc/nginx/sites-enabled/default

Your original server block should already be defined. Depending on which direction you want to redirect, use one of the following options.

Option 1: Redirect www to non-www

If you want redirect users from www to a plain, non-www domain, insert this configuration:

New Server Block — www to non-www
server {
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

Save and exit. This configures Nginx to redirect requests to “www.example.com” to “example.com”. Note that there should be another server block that defines your non-www web server.

To put the changes into effect, restart Nginx:

sudo service nginx restart

Note that if you are using HTTPS, the listen directive should be set to port 443 instead of 80.

Use this curl command to ensure that the non-www domain redirects to the www domain (replace the highlighted part with your actual domain):

curl -I http://www.example.com

You should get a 301 Moved Permanently response, that shows the non-www redirect location, like this:

Output:
HTTP/1.1 301 Moved Permanently Server: nginx/1.4.6 (Ubuntu) Date: Mon, 04 May 2015 18:20:19 GMT Content-Type: text/html Content-Length: 193 Connection: keep-alive Location: http://example.com/

Of course, you should access your domain in a web browser (www and non-www) to be sure.

Option 2: Redirect non-www to www

If you want redirect users from a plain, non-www domain to a www domain, add this server block:

New Server Block — non-www to www
server {
    server_name example.com;
    return 301 $scheme://www.example.com$request_uri;
}

Save and exit. This configures Nginx to redirect requests to “example.com” to “www.example.com”. Note that there should be another server block that defines your www web server.

To put the changes into effect, restart Nginx:

sudo service nginx restart

Note that if you are using HTTPS, the listen directive should be set to port 443 instead of 80.

Use this curl command to ensure that the non-www domain redirects to the www domain (replace the highlighted part with your actual domain):

curl -I http://example.com

You should get a 301 Moved Permanently response, that shows the www redirect location, like this:

Output:
HTTP/1.1 301 Moved Permanently Server: nginx/1.4.6 (Ubuntu) Date: Mon, 04 May 2015 18:20:19 GMT Content-Type: text/html Content-Length: 193 Connection: keep-alive Location: http://www.example.com/

Of course, you should access your domain in a web browser (www and non-www) to be sure.

Conclusion

That’s it! Your Nginx permanent redirect is now configured properly, and your users will be able to access your web server via your non-www and www domain.


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
10 Comments

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;
        }
}