0

There are many good results out there on how to redirect "www" to "non-www" and visa versa.

The most recommended solution is this:

server {
    listen 80;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

This works well for a single website configuration file. However, it quickly duplicates configuration when you have multiple websites under one Nginx server.

I'd really like to avoid duplicating configuration on a service I'm working on...

So my assumed solution to catch all www.[anything.com] domains looks something like this:

server {
    listen 80;
    return 301 https://$host$request_uri;
}

However, I believe the $host variable still contains "www" inside (which makes sense).

I'm struggling to test this with my current configuration, so to save time, please could someone with more Nginx experience point me in the right direction beyond this point?

Thank you for your time!

3 Answers3

2

You can use the following approach:

server {
    listen 80;
    server_name ~^(?:www\.)(.*)$;

    return 301 https://$1$request_uri;
}

The regular expression captures the part after www. to $1 variable, which is then used in the return statement.

https://nginx.org/r/server_name explains in more details how nginx decides which server block to use.

Pothi Kalimuthu
  • 5,734
  • 2
  • 24
  • 37
Tero Kilkanen
  • 34,499
  • 3
  • 38
  • 58
  • 1
    And remember to include an ssl `server` block with the appropriate certificate(s). – Michael Hampton Jun 14 '21 at 15:28
  • This is very powerful thank-you! I will mark this as the correct answer to this question. I would however be curious if there's a non regex solution out there to improve the performance? – Matthew Spence Jun 14 '21 at 15:46
  • No there isn't, because you need to extract part of the hostname, and regex is the only way to do it. – Tero Kilkanen Jun 14 '21 at 15:50
0
server { 

         server_name example.com; 

         return 301 https://www.example.com$request_uri; 

}

By default, if you omit this directive, nginx assume that you want listen on port 80.

Here the documentation of this default behavior.

Here the complete config for your default-ssl.conf

server {

 listen 443 ssl;

 server_name example.com; 

ssl_certificate /srv/www/example.com/keys/ssl.crt; 

ssl_certificate_key /srv/www/example.com/keys/www.example.com.key; 

return 301 https://www.example.com$request_uri; 

}

You can replace ssl on; directive with listen 443 ssl; as recommendation from nginx documentation.

Nikhil
  • 88
  • 4
  • Thank you for your answer. Unfortunately this does not help in the effort of making a "catch all" solution so you don't need to write configuration per domain (as you would with yours here only working for `example.com` and not also `example-2.com`) – Matthew Spence Jun 14 '21 at 15:42
0

Welcome to ServerFault.

While what Tero Kilkanen answered is the core concept, a nicer way to do the same is already provided in the official documentation at https://nginx.org/r/server_name and at https://nginx.org/en/docs/http/server_names.html.

server {
    server_name ~^www\.(?<baredomain>.+)$;
    return 301 https://$baredomain$request_uri;
}

This uses a method called "Named Captures" while evaluating a regular expression. The "named captures" can use any of the following syntax...

?<name> Perl 5.10 compatible syntax, supported since PCRE-7.0
?'name' Perl 5.10 compatible syntax, supported since PCRE-7.0
?P<name>    Python compatible syntax, supported since PCRE-4.0
Pothi Kalimuthu
  • 5,734
  • 2
  • 24
  • 37