Is it Possible to Dynamically Return an SSL Certificate in NodeJS?

Yes, it is possible to do it with one server. But the caveat is that it works on clients that support SNI – which is most modern browsers.

This is how you do it:


    //function to pick out the key + certs dynamically based on the domain name
    function getSecureContext (domain) {
        return crypto.createCredentials({
            key:  fs.readFileSync('/path/to/domain.key'),
            cert: fs.readFileSync('/path/to/domain.crt'),
            ca: [
                fs.readFileSync('/path/to/CA_cert_1.crt'), 
                fs.readFileSync('/path/to/CA_cert_2.crt'), 
                // <include all CA certs that you have to> ... 
            ]
          }).context;
    }

    //read them into memory
    var secureContext = {
        'domain1': getSecureContext('domain1'),
        'domain2': getSecureContext('domain2'),
        // etc
    }

    //provide a SNICallback when you create the options for the https server
    var options = {
        SNICallback: function (domain) {
            return secureContext[domain];
        }, // SNICallback is passed the domain name, see NodeJS docs on TLS
        cert: fs.readFileSync('/path/to/server.crt'),
        key: fs.readFileSync('/path/to/server.key'),                
        }
    }

    //create your https server
    var server = require('https').createServer(options, [requestListener]);
    //using Express
    var server = require('https').createServer(options, require('express')());
    server.listen(<someport>);

This works because the options for https is similar to tls.createServer(). Make sure you include all required CA intermediate and root certificates in the crypto.createCredentials call. Also if you have a CA bundle, split them up into multiple single crt files before using them as ‘ca’ accepts an array of certificates.

Leave a Comment