skip to Main Content

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

}

2

Answers


  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....
    
    }
    
    Login or Signup to reply.
  2. 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;).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search