How to get nginx to redirect from www to non-www domain?

I also looked at this on the Nginx wiki and other blogs and the best way performance wise is to do the following:

To redirect from www.example.com to example.com using nginx (version 1.0.12 at time of writing).

server {
  server_name www.example.com;
  rewrite ^ $scheme://example.com$request_uri permanent; 
  # permanent sends a 301 redirect whereas redirect sends a 302 temporary redirect
  # $scheme uses http or https accordingly
}

server {
  server_name example.com;
  # the rest of your config goes here
}

When requests come to example.com, no if statements are used for performance. And it uses $request_uri rather than having to create a $1 match which taxes the rewrite (see Nginx Common Pitfalls page).

Sources:

  • https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#server-name-if
  • http://wiki.nginx.org/NginxHttpCoreModule#.24scheme

After some digging around and some missteps, here is the solution. The gotcha I ran into is to make sure to use "http://example.com$uri". Inserting a / in front of $uri results in a redirect to http://example.com//

  server {
    listen 80;
    server_name www.example.com;
    rewrite ^ http://example.com$uri permanent;
  }

  # the server directive is nginx's virtual host directive.
  server {
    # port to listen on. Can also be set to an IP:PORT
    listen 80;

    # Set the charset
    charset utf-8;

    # Set the max size for file uploads to 10Mb
    client_max_body_size 10M;

    # sets the domain[s] that this vhost server requests for
    server_name example.com;

    # doc root
    root /var/www/example.com;

    # vhost specific access log
    access_log  /var/log/nginx_access.log  main;


    # set vary to off to avoid duplicate headers
    gzip off;
    gzip_vary off;


    # Set image format types to expire in a very long time
    location ~* ^.+\.(jpg|jpeg|gif|png|ico)$ {
        access_log off;
        expires max;
    }

    # Set css and js to expire in a very long time
    location ~* ^.+\.(css|js)$ {
        access_log off;
        expires max;
    }

    # Catchall for everything else
    location / {
      root /var/www/example.com;
      access_log off;

      index index.html;
      expires 1d;

      if (-f $request_filename) {
        break;
      }
    }
  }

Please visit this question in SO: https://stackoverflow.com/a/11733363/846634

From the better answer:

Actually you don't even need a rewrite.

server {
    #listen 80 is default
    server_name www.example.com;
    return 301 $scheme://example.com$request_uri;
}

server {
    #listen 80 is default
    server_name example.com;
    ## here goes the rest of your conf...
}

As my answer is getting more and more up votes but the above as well. You should never use a rewrite in this context. Why? Because nginx has to process and start a search. If you use return (which should be available in any nginx version) it directly stops execution. This is preferred in any context.