0

I've read in Nginx docummentation that instead of using IFs, new server blocks should be made.

I have tried making another block listening to 443 ssl, just to set there redvi.eu (non www) and then redirect it accordingly. It fails because of duplication.

How is the correct way to redirect https non-www here?

server { listen 80 default_server; server_name www.redvi.eu redvi.eu; return 301 https://www.redvi.eu$request_uri; } server { server_name www.redvi.eu; root /home/deploy/redvi/current/public; passenger_enabled on; passenger_app_env production; location /cable { passenger_app_group_name redvi_websocket; passenger_force_max_concurrent_requests_per_process 0; } # Allow uploads up to 100MB in size client_max_body_size 100m; location ~ ^/(assets|packs) { expires max; gzip_static on; } listen [::]:443 ssl ipv6only=on; # managed by Certbot listen 443 ssl; # managed by Certbot ssl_certificate /etc/letsencrypt/live/www.redvi.eu/fullchain.pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/www.redvi.eu/privkey.pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot } 
3
  • 1
    You'd need three server blocks to do it. Here is an example for redirecting www to non-www; you'd need to do the opposite thing. Commented Jun 6, 2022 at 19:23
  • Thanks for answering. Do I really need certificates definitions in the first block if the only thing I will do is to redirect? Commented Jun 6, 2022 at 19:32
  • 1
    Nginx will refuse to start if the server block listening on ssl-enabled port wouldn't have the certificate/key declaration. Commented Jun 6, 2022 at 19:34

2 Answers 2

1

I think I have to comment the difference between the accepted answer and my suggestion. Of course you can use two server blocks with the additional string comparsion operation during the NGX_HTTP_SERVER_REWRITE request processing phase. Moreover, you can even use a single server block like the following one:

server { listen 80; listen [::]:80; listen 443 ssl; listen [::]:443 ssl; server_name example.com www.example.com; # ssl certificate/key/ciphers setup if ($https = "") { return 301 https://www.example.com$request_uri; } if ($http_host != www.example.com) { return 301 https://www.example.com$request_uri; } ... # rest of configuration here } 

Nevertheless my advice to use three server blocks was given intentionally because of the performance considerations. That's because internally nginx will build a hash table for each subdomain level to select the proper server block via hash table(s) lookup with a complexity not bigger than O(x) where x is a maximum number of subdomain components for a longest hosted server name (e.g. 3 for the www.example.com). This is the same algorithm that is used to evaluate a map block with the hostnames keyword specified, and explanations about its performance was given by nginx lead developer Igor Sysoev here. Configuring nginx, especially on a high loaded system, you should not try to shorten your config in cost of performance. Nginx configuration is (mostly) declarative, it isn't a script or program code, nginx isn't an optimizing compiler to process your configuration most optimal way. The DRY (don't repeat yourself) principles aren't applicable here even if you got such a temptation.


In some examples you can even see something like:

if ($http_host !~ ^www\.) { rewrite ^ https://www.$http_host$request_uri permanent; } 

This one is the worst in the performance terms because of an expensive PCRE library call being invoked (actually even two calls when a rewrite directive used in the above example instead of the return 301 https://www.$http_host$request_uri;).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for such detailed explanation. I understand now. I struggle getting different certificated for different domains and my application is not super high load. Sometimes I value something pragmatic for each stage, but I always appreciate the full and correct answer.
1

Even if you don't want to use "IF", there's not much you can do.

I've been using it this way for many years and it works well.

server { listen 80; listen [::]:80; server_name example.com www.example.com; return 301 https://www.example.com$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name example.com www.example.com; root /var/www/sites/example.com/public; if ($host != 'www.example.com') { return 301 https://www.example.com$request_uri; } # others.... } 

1 Comment

I was convinced that you needed 3 blocks, but yes, that worked as a charm

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.