Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove www. from host name using Nginx Rewrite

Tags:

nginx

rewrite

I am trying to configure my Nginx to strip out www. from hostname. I am looking for generic rule that handle possible subdomain cases.

E.g. If http://www.foo1.sample.com and http://www.fooX2.sample.com are two domains.

Then I want to strip any www. before such subdomains, and redirect them to http://foo1.sample.com and http://fooX2.sample.com respectively (WITHOUT knowing the exact subdomain in the rule.)

Thanks.

like image 512
Tzahi Fridman Avatar asked Apr 28 '13 18:04

Tzahi Fridman


2 Answers

Best Practice:

The best practice, as well as the most efficient way, would be to use a separate server definition for this.

This will not only ensure that the config is automatically applied to every single one of the websites that are hosted on your nginx instance, but it'll also makes sure that you don't end up running regular expressions on the hostname from multiple instances in your code.

The following is the simplest form:

server {
    listen      80;
    server_name ~^www\.(?<domain>.+)$;
    return  301 $scheme://$domain$request_uri;
}

If you do use https, then things get more complicated, because you'd have to ensure that the certificates don't mismatch. Unless you have a single certificate for all of your domains, it would be the best practice to simply hardcode everything, as it's already hardcoded in the certificate anyways, and a solution like above simply isn't possible due to the certificate requirements.


Alternative:

Note that the other answer to the question, which uses rewrite ^(.*) http://…$1 …, is incorrect, and will cause you to lose $query_string, as well as potentially mangle the encoding of the request as per Nginx pass_proxy subdirectory without url decoding.

If you require an if-based approach and no hardcoding, neither of which are recommended, e.g., like the other answer, then at least use the correct paradigm, to avoid the bloat and the loss of the $query_string; note that as per nginx server name regex when "Host" header has a trailing dot, the $host variable is already normalised by nginx (trailing dot removed, whole thing brought to lower case), so, you don't need to worry about doing a case-insensitive comparison like in the other answer, either:

if ($host ~ ^www\.(?<domain>.+)$) {
    return  301 $scheme://$domain$request_uri;
}

References:

  • http://nginx.org/r/listen
  • http://nginx.org/r/server_name
  • http://nginx.org/r/return
  • http://nginx.org/en/docs/http/server_names.html
like image 178
cnst Avatar answered Nov 16 '22 15:11

cnst


I think adding following If block in your Nginx conf file should work for you. It also takes care of subdomain case you mentioned.

if ($host ~* ^www\.(.*)) {       
    set $host_without_www $1;
    rewrite ^(.*) http://$host_without_www$1 permanent;
}
like image 14
lalit Avatar answered Nov 16 '22 17:11

lalit