Redirect all www-prefixed requests to non-www in Nginx

Redirecting all www-prefixed requests to a non-www address in Nginx is easy with the following catch-all configuration.

server {
  server_name ~^www\.(.+)$;
  return 301 $scheme://$1$request_uri;
}

Here we create a server block and define the server_name.

We start the server_name with a tilde character (~) which means that Nginx should treat the name as a regular expression instead of an exact string.

After the tilde comes the actual regular expression where ^ means the beginning and $ the end of the expression. These are called anchors.

Between anchors is a raw string “www” and then a dot. We have to escape the dot using a backslash because it’s a character that otherwise has a special meaning in regular expressions.

And speaking of that, next we have a dot and then a plus sign. Dot matches basically any character except a line break. The plus sign immediately after that means that we want to match 1 or more characters. And we put this in parentheses to capture the string that’s inside them so we can use it later in the next line.

In the second line we specify a return directive that returns the specified HTTP code 301 (permanent redirect) to a client, following by a URL to where we want to redirect the client.

In the URL we use a variable $scheme that has a value ‘http’ or ‘https’. We could replace the $scheme with a raw string ‘https’ if we want to force the redirection always to the https-URL. Variable $1 is the string we captured in the previous line and it’s basically the domain name without the www-prefix. And finally we have a $request_url which is the rest of the request (the path part that comes after the domain name).

Where to put this configuration?

Usually Nginx is configured inside the /etc/nginx directory and inside the /etc/nginx/nginx.conf file. The server block should always go inside the main http block, like this:

http {
  server {
  }
}

Otherwise it shouldn’t matter where you actually put the redirection.

Please notice that if you have many server blocks of which server_names are matching with the request, Nginx picks up first the server block that has an exact name (like www.example.com) or a wildcard name (like *.example.com). Regular expression names (like ~^www\.example\.com$) match after them.

What if I have numbers in the subdomain like www1.example.com?

If you have numbers in subdomains (like www1 and www2) and want to match them with a regular expression, you can use \d for that. It matches for any digit. If it’s possible to have more than one digit, then just use the plus sign we used earlier. And if you want match www-subdomains with and without numbers, you can replace the plus sign with an asterisk. That means we want to match 0 or more digits.

server {
  server_name ~^www\d*\.(.+)$;
  return 301 $scheme://$1$request_uri;
}