An auto-sni strategy for registering and renewing letsencrypt / ACME certificates using SNICallback.
Go to file
Ben Schmidt 7f826369a6 support uncaching and non-automatic certificates
This facilitates temporarily installing certificates to satisfy TLS SNI
challenges.

Promises are also shared to avoid simultaneously obtaining certificates
when initially loading/registering one or after expiry.
2016-10-08 22:09:19 +11:00
.gitignore Initial commit 2016-08-10 14:37:09 -06:00
LICENSE Initial commit 2016-08-10 14:37:09 -06:00
README.md support uncaching and non-automatic certificates 2016-10-08 22:09:19 +11:00
index.js support uncaching and non-automatic certificates 2016-10-08 22:09:19 +11:00
package.json v2.0.1 2016-08-12 01:59:25 -04:00
test.js support uncaching and non-automatic certificates 2016-10-08 22:09:19 +11:00

README.md

le-sni-auto

An auto-sni strategy for registering and renewing letsencrypt certificates using SNICallback.

This does a couple of rather simple things:

  • caches certificates in memory
  • calls getCertificatesAsync(domain, null) when a certificate is not in memory
  • calls getCertificatesASync(domain, certs) when a certificate is up for renewal or expired

Install

npm install --save le-sni-auto@2.x

Usage

With node-letsencrypt

'use strict';



var leSni = require('le-sni-auto').create({

  renewWithin: 10 * 24 * 60 * 60 1000       // do not renew more than 10 days before expiration
, renewBy: 5 * 24 * 60 * 60 1000         // do not wait more than 5 days before expiration

, tlsOptions: {
    rejectUnauthorized: true              // These options will be used with tls.createSecureContext()
  , requestCert: false                    // in addition to key (privkey.pem) and cert (cert.pem + chain.pem),
  , ca: null                              // which are provided by letsencrypt
  , crl: null
  }

});



var le = require('letsencrypt').create({
  server: 'staging'

, sni: leSni

, approveDomains: function (domain, cb) {
    // here you would lookup details such as email address in your db
    cb(null, { email: 'john.doe@gmail.com.', domains: [domain, 'www.' + domain], agreeTos: true }}
  }
});



var redirectHttps = require('redirect-https').create();
http.createServer(le.middleware(redirectHttps));



var app = require('express')();
https.createServer(le.httpsOptions, le.middleware(app)).listen(443);

You can also provide a thunk-style getCertificates(domain, certs, cb).

Standalone

'use strict';



var leSni = require('le-sni-auto').create({
  renewWithin: 10 * 24 * 60 * 60 1000       // do not renew prior to 10 days before expiration
, renewBy: 5 * 24 * 60 * 60 1000         // do not wait more than 5 days before expiration

  // key (privkey.pem) and cert (cert.pem + chain.pem) will be provided by letsencrypt
, tlsOptions: { rejectUnauthorized: true, requestCert: false, ca: null, crl: null }

, getCertificatesAsync: function (domain, certs) {
    // return a promise with an object with the following keys:
    // { privkey, cert, chain, expiresAt, issuedAt, subject, altnames }
  }
});



// some default certificates that work with localhost
// (because default certificates are required as a fallback)
var httpsOptions = require('localhost.daplie.com-certificates').merge({
  SNICallback: leSni.sniCallback
});

https.createServer(httpsOptions, app);

You can also provide a thunk-style getCertificates(domain, certs, cb).

API

  • create(options)
    • getCertificates(domain, certs, cb) or getCertificatesAsync(domain, certs)
    • renewWithin (default 7 days, min 3 days)
    • renewBy (default 2 days, min 12 hours)
  • sniCallback(domain, cb)
  • cacheCerts(certs)
  • uncacheDomain(domain)

.renewWithin

Specifies the maximum amount of time (in ms) before the certificate expires to renew it.

Say the cert expires in 90 days and you would like to renew, at earliest 10 days before it expires.

You would set this to 10 * 24 * 60 * 60 * 1000.

.renewBy

Specifies the maximum amount of time (in ms) before the certificate expires to renew it.

Say the cert expires in 90 days and you would like to renew, at latest 10 days before it expires.

You would set this to 10 * 24 * 60 * 60 * 1000.

MUST be less than renewWithin.

.sniCallback()

This gets passed to https.createServer(httpsOptions, app) as httpsOptions.SNICallback.

var leSni = require('le-sni-auto').create({
  renewWithin: 10 * 24 * 60 * 60 1000
});

var httpsOptions = require('localhost.daplie.com-certificates').merge({
  SNICallback: leSni.sniCallback
});

function app(req, res) {
  res.end("Hello, World!");
}

https.createServer(httpsOptions, app);

.cacheCerts()

Manually load a certificate into the cache.

This is useful in a cluster environment where the master may wish to inform multiple workers of a new or renewed certificate, or to satisfy tls-sni-01 challenges.

leSni.cacheCerts({
, privkey: '<<privkey.pem>>'
, cert: '<<cert.pem + chain.pem>>'
, subject: 'example.com'
, altnames: [ 'example.com', 'www.example.com' ]
, issuedAt: 1470975565000
, expiresAt: 1478751565000
, auto: true
});

.uncacheCerts()

Remove cached certificates from the cache.

This is useful once a tls-sni-01 challenge has been satisfied.

leSni.uncacheCerts({
, subject: 'example.com'
, altnames: [ 'example.com', 'www.example.com' ]
});