nginx

Nginx TLS-SNI: Use hostname dependent SSL for HTTPS


I need to use two different ssl certs with nginx pointing to the same app.

https://domain1.com points to 1.1.1.1
https://domain2.com points to 1.1.1.1 .
.
.
.
https://domainN.com points to 1.1.1.1

Tried the following:

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

server {
    listen 443 ssl;
    server_name domain1.com;
    root /app/dist;

    index index.html;

    ssl_certificate /etc/nginx/ssl/d1/certificate.crt;
    ssl_certificate_key /etc/nginx/ssl/d1/private.key;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

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

server {
    listen 443 ssl;
    server_name domain2.com;
    root /app/dist;

    index index.html;

    ssl_certificate /etc/nginx/ssl/d2/certificate.crt;
    ssl_certificate_key /etc/nginx/ssl/d2/private.key;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

This doesn't work, it just loads the first cert resulting in invalid cert when accessed using the second domain.

The domain certs can't be combined. I can't spin two different instances for nginx as the case needs to help me out with n-Domains pointing to same IP preferably using one nginx server.

Is there a way out?


Solution

  • Thanks to Richard Smith for pointing out just the right stuff!

    So, to setup nginx to use different cert-key pair for domains pointing to the same nginx we have to rely on TLS-SNI (Server Name Indication), where the domain name is sent un-encrypted text as a part of the handshake. This helps nginx to decide which cert-key pair to use for the incoming secure request.

    More can be read about SNI here.

    Moving on to the configuration.

    server {
    listen 80;
    server_name domain1.com;
    return 301 https://$server_name$request_uri;
    }
    
    
    
    server {
    
        listen 443 ssl;
        server_name domain1.com;
        root /app/dist;
        index index.html;
        ssl_certificate /etc/nginx/ssl/d1/certificate.crt;
        ssl_certificate_key /etc/nginx/ssl/d1/private.key;
    
        location / {    
            try_files $uri $uri/ /index.html;
        }
    }
    
    
    server {
    listen 80;
    server_name domain2.com;
    return 301 https://$server_name$request_uri;
    }
    
    
    
    server {
    
        listen 443 ssl;
        server_name domain2.com;
        root /app/dist;
        index index.html;
        ssl_certificate /etc/nginx/ssl/d2/certificate.crt;
        ssl_certificate_key /etc/nginx/ssl/d2/private.key;
    
        location / {    
            try_files $uri $uri/ /index.html;
        }
    }
    

    The above config forwards HTTP (80) for both domain1 and domain2 to respective HTTPS (443) server blocks, where respective cert-key pairs are loaded.
    The HTTPS (443) request is handled directly.
    nginx decides which block to hit by picking the server name using SNI.