Score:0

Nginx - How do I force all server domains and server blocks to use non-www redirect?

de flag

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!

Score:2
us flag

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.

Michael Hampton avatar
cz flag
And remember to include an ssl `server` block with the appropriate certificate(s).
Matthew Spence avatar
de flag
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?
us flag
No there isn't, because you need to extract part of the hostname, and regex is the only way to do it.
Score:0
sv flag

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
Score:0
ar flag
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.

Matthew Spence avatar
de flag
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`)
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.