Redundant host names on Nginx and Apache

Shortly after switching my site from Wordpress over to Ghost I was taking a look at Google Analytics and noticed this alert:

Property http://www.netinstructions.com is receiving data from redundant hostnames. Consider setting up a 301 redirect on your website, or make a search and replace filter that strips "www." from hostnames. Examples of redundant hostnames: example.com, www.example.com.

Okay, I must have overlooked that in the migration. I didn't think it was that big of a deal until I read the section on redirects here regarding SEO. The solution involves a simple Nginx or Apache change (depending on which web server you have) that I explain at the bottom. I also include a way to figure out which server you have, and a way to test/verify the change.

But first, I had to decide which I preferred...

To use www or to not use www

This turned out to be the more difficult question. I found no less than three versions of this question on various stack exchange websites:

Not only that, but apparently someone felt so strongly about this issue that they went and created a whole website about the topic suitably named no-www.org.

And then I learned that someone felt so strongly about having the www subdomain that there's a website dedicated entirely to the inverse, named www.yes-www.org

So... what the heck? Did I stumble upon something similar to the Emacs vs. Vi (Vim) debate? Curly braces on this line or the next line? Tabs or spaces?

Oh well! People will disagree on things and I'm glad we have the discussion.

I decided to direct netinstructions.com requests to www.netinstructions.com since I like the extra verbosity and the bit about the cookies made sense. Also the no-www website made my eyes hurt.

Removing (or adding) www on Nginx

My file was located at /etc/nginx/sites-available/www.netinstructions.com that I edited.

If you want to add the www on Nginx (this is what I decided to do):

 server {
    server_name example.com;
    return 301 http://www.example.com$request_uri;
}
server {
    server_name  www.example.com;
    // Anything else here...
}

On the other hand, to remove the www and redirect to the non-www domain on Nginx:

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

There's more information at this stackoverflow discussion which also discusses the slight differences if it's over HTTPS, or you can read the nginx docs or nginx pitfalls wiki

Also, don't forget to restart or reload Nginx by typing sudo service nginx reload

Removing (or adding) www on Apache

You can copy these rules to the .htaccess file.

To remove www on Apache:

RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%2://%1%{REQUEST_URI} [L,R=301]

Or to add www on Apache:

RewriteCond %{HTTP_HOST} !^www\.
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

The above are discussed here and I also found this slightly newer answer.

Verifying the fix

Before I made the change I did two simple curl requests (curl is a unix command). Regardless of your webserver, you should see a redirect happening after you make this fix. If you're not sure which webserver you have, you can also use curl to find out

$ curl -I -L http://netinstructions.com
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 13 Jan 2015 03:57:08 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 8968
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
ETag: W/"sTDclBz1wzhztqkd6TLTbg=="
Vary: Accept-Encoding

And with the www:

$ curl -I -L http://www.netinstructions.com
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 13 Jan 2015 03:57:19 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 8968
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
ETag: W/"sTDclBz1wzhztqkd6TLTbg=="
Vary: Accept-Encoding

Now, after I made the change (and reloaded Nginx) I performed the same requests. Since I decided to always add the www, you'll see the 301 redirect when I make a request to the non-www domain netinstructions.com

$ curl -I -L http://netinstructions.com
HTTP/1.1 301 Moved Permanently <-------- Success!
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 13 Jan 2015 04:08:27 GMT
Content-Type: text/html
Content-Length: 193
Connection: keep-alive
Location: http://www.netinstructions.com/

HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 13 Jan 2015 04:08:27 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 8968
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
ETag: W/"sTDclBz1wzhztqkd6TLTbg=="
Vary: Accept-Encoding

And with the www (should expect no changes for my case, since I want www to always be used):

$ curl -I -L http://www.netinstructions.com
HTTP/1.1 200 OK
Server: nginx/1.4.6 (Ubuntu)
Date: Tue, 13 Jan 2015 04:08:34 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 8968
Connection: keep-alive
X-Powered-By: Express
Cache-Control: public, max-age=0
ETag: W/"sTDclBz1wzhztqkd6TLTbg=="
Vary: Accept-Encoding

Perfect. All done.