How do I redirect an request at www. to the non-www version?
This should include requests to the root domain as well as any (wildcard) subdomain.
I also don't want any unnecessary if statements, as per the nginx pitfalls document.
Here's what I have so far but it only seems to work for the root domain, not subdoamins.
server {
listen 80 default_server;
server_name www.*;
rewrite "^www\.(.*)" $scheme://$1 permanent;
}
There are a couple of ways to do this. Set up a configuration file for www.servername.org domain name, and give it a general redirect to servername.org OR add the following into your config instead of your rewrite line.
My understanding of your question is the following: Redirect all requests reaching any subdomain of an arbitrary root domain to the root domain - in a reasonably general manner. For example:
Let's start with the easy case first - a known root domain, with any subdomain:
This is fairly well optimized - no if statements, no unnecessary captures in the rewrite - and wildcard server_names are hashed for performance. The first server block matches any subdomain and will issue a redirect to the second server block which only matches the root domain. (Note, although it is easy to match both conditions in one server block (
server_name .example.com
- no*
needed) the two server blocks are needed to prevent a redirect loop).The more generalized case requires some way of identifying the domain, since it is 'unknown'. We therefore need to parse the server_name - and can do so with a regex capture.
Here we have a (required) subdomain -
(.+\.)
means any character (.
) repeated one or more times (+
) followed by an actual '.' (escaped with the backslash) - this capture will be assigned to$1
if we need it.The next section is very similar - we are using Perl 5.1/PCRE7 notation for a 'named capture' -
?<domain>
assigns the capture to$domain
. Our domain can be anything (.
) one or more characters in length (+
), followed by an actual '.' and then another set of any characters (the TLD). This regex will not work for TLDs which contain a '.' - e.g. 'co.uk' - if you will be using those, it is probably best to specify the valid TLDs in your regex. For example:We use the same rewrite as above, just replacing the static root domain with the captured domain.
Since a common case with the 'unknown' domain scenario will see you passing the same files to all the domains, you probably don't need to capture the domain name in the default_server block (it is more efficient to avoid the regex when possible).
It is important to note that regex matches have the lowest priority - exact names, and wildcard entries take precendence over regexes. Additionally, unlike exact names and wildcard entries - regexes are not hashed. Finally, when using regexes with captures, even if only one server block is defined, the expression must be evaluated for every request to obtain the captures.
As a result of the above, if you do have to do something specific with a particular domain name, simply define a new server block for it and that will take precedence over the default_server block defined above.
If you know the domain names, even if they are numerous, you will get better performance if you can include the static name instead of using a regex. That said, there are some cases (e.g. allowing users to point their (unknown) domain at your IP as part of a service) where you may not know the domain and where the regex approach is necessary.
(Of course, this needs a matching wildcard DNS entry for the requests to ever reach the server.)
Keep it simple.
http://nginx.org/en/docs/http/server_names.html
Better still
Or is this too simple?