0

I have a VPS with 14 domains and I setup letskencrypt to automatically retrieve a separate certificate for each domain with all sub-domains included. So, I have 14 certs. Obviously, putting all domains in one cert is not an option because soon I'll hit the maximum 100 domain/sub-domain per cert for Letsencrypt.

So, I was happy for a month until I found out that nginx serves wrong certs for all domains except one (the one that it automatically picks up - or, I'll set - as the default server for port 443). After a lot of headache I found out that each SSL cert must have its own IP not a shared one. Then also I found out there is SNI as a workaround for this issue.

$ nginx -V
TLS SNI support enabled

So make the long story short; The problem is no matter what I do nginx stubbornly serve's the wrong cert:

$ curl --insecure -v https://babaei.net 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host babaei.net left intact

$ curl --insecure -v https://learnmyway.net 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host learnmyway.net left intact

$ curl --insecure -v https://3rr0r.org 2>&1 | awk 'BEGIN { cert=0 } /^\* Server certificate:/ { cert=1 } /^\*/ { if (cert) print }'
* Server certificate:
*  subject: CN=babaei.net
*  start date: Aug 28 13:30:00 2016 GMT
*  expire date: Nov 26 13:30:00 2016 GMT
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok.
* Connection #0 to host 3rr0r.org left intact

And, don't get me wrong the actual certs are what they are supposed to be:

$ openssl x509 -noout -subject -in /path/to/certs/babaei.net.pem
subject= /CN=babaei.net

$ openssl x509 -noout -subject -in /path/to/certs/learnmyway.net.pem
subject= /CN=learnmyway.net

$ openssl x509 -noout -subject -in /path/to/certs/3rr0r.org.pem
subject= /CN=3rr0r.org

So, let's say we have two domains alpha.com and omega.com. How would you configure SNI enabled nginx to serve the right SSL cert for each?

server {
  server_tokens  off;

  listen  443 ssl http2;
  listen  [::]:443 ssl http2;
  server_name  www.alpha.com;

  ssl  on;
  ssl_certificate  /path/to/alpha.com/cert.pem;
  ssl_certificate_key /path/to/alpha.com/key.pem;
}

server {
  server_tokens  off;

  listen  443 ssl http2;
  listen  [::]:443 ssl http2;
  server_name  www.omega.com;

  ssl  on;
  ssl_certificate  /path/to/omega.com/cert.pem;
  ssl_certificate_key /path/to/omega.com/key.pem;
}

Thanks

UPDATE: This was the original config:

server {
    server_tokens   off;

    listen          80;
    listen          [::]:80;
    server_name     learnmyway.net;

    location / {
        return 301 https://www.$server_name$request_uri;  # enforce https / www
    }

    # Error Pages
    include /path/to/snippets/error;

    # Anti-DDoS
    include /path/to/snippets/anti-ddos;

    # letsencrypt acme challenges
    include /path/to/snippets/letsencrypt-acme-challenge;
}

server {
    server_tokens   off;

    listen          80;
    listen          [::]:80;
    server_name     *.learnmyway.net;

    location / {
        return 301 https://$host$request_uri;  # enforce https
    }

    # Error Pages
    include /path/to/snippets/error;

    # Anti-DDoS
    include /path/to/snippets/anti-ddos;

    # letsencrypt acme challenges
    include /path/to/snippets/letsencrypt-acme-challenge;
}


server {
    server_tokens   off;

    listen          443 ssl http2;
    listen          [::]:443 ssl http2;
    server_name     www.learnmyway.net;

    # Hardened SSL
    include                 /path/to/snippets/hardened-ssl;
    ssl_certificate         /path/to/certs/learnmyway.net.pem;
    ssl_certificate_key     /path/to/keys/learnmyway.net.pem;
    ssl_trusted_certificate /path/to/certs/learnmyway.net.pem;

    #error_log      /path/to/learnmyway.net/log/www_error_log;
    #access_log     /path/to/learnmyway.net/log/www_access_log;

    root            /path/to/learnmyway.net/www/;
    index           index.html;

    # Error Pages
    include         /path/to/snippets/error;

    # Anti-DDoS
    include         /path/to/snippets/anti-ddos;

    # letsencrypt acme challenges
    include /path/to/snippets/letsencrypt-acme-challenge;

    # Compression
    include         /path/to/snippets/compression;

    # Static Resource Caching
    include         /path/to/snippets/static-resource-caching;
}
  • 1
    Do you have server blocks for all of your domains? – Alexey Ten Aug 29 '16 at 9:36
  • Right. Show the actual nginx configuration for these domains. – Michael Hampton Aug 29 '16 at 9:36
  • 1
    In your config you don't need ssl on; directives and SHOULD add alpha.com and omega.com names to corresponding server_name directives. Oherwise request to omega.com (without www) will end up in first server block. – Alexey Ten Aug 29 '16 at 9:37
  • 1
    It was solved? I don't see your answer below! – Michael Hampton Sep 4 '16 at 14:39
  • 1
    @MichaelHampton the answer was in the update section. But to avoid confusion as you asked I did add it as an answer. – Mohammad S. Babaei Sep 5 '16 at 17:06
1

Looks like @AlexeyTen was right. Adding the following server block solved the issue:

server {
    server_tokens   off;

    listen          443 ssl http2;
    listen          [::]:443 ssl http2;
    server_name     learnmyway.net;

    # Hardened SSL
    include                 /path/to/snippets/hardened-ssl;
    ssl_certificate         /path/to/certs/learnmyway.net.pem;
    ssl_certificate_key     /path/to/keys/learnmyway.net.pem;
    ssl_trusted_certificate /path/to/certs/learnmyway.net.pem;

    return 301 https://www.$server_name$request_uri;  # enforce www
}

My mistake: Since * is a wildcard character, I thought *.learnmyway.net will resolve learnmyway.net, too. It seems I was wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.