Greenlock Cluster -> Greenlock Express v3
This commit is contained in:
parent
76cbd1e52a
commit
edb882e792
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"useTabs": false
|
||||||
|
}
|
194
README.md
194
README.md
|
@ -1,3 +1,41 @@
|
||||||
|
# Replaced: Use Greenlock Express v3
|
||||||
|
|
||||||
|
See https://git.rootprojects.org/root/greenlock-express.js
|
||||||
|
|
||||||
|
```js
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var pkg = require("./package.json");
|
||||||
|
require("greenlock-express")
|
||||||
|
.init(function getConfig() {
|
||||||
|
// Greenlock Config
|
||||||
|
|
||||||
|
return {
|
||||||
|
package: { name: pkg.name, version: pkg.version },
|
||||||
|
maintainerEmail: pkg.author,
|
||||||
|
|
||||||
|
// put cluster on full throttle!
|
||||||
|
cloudnative: true
|
||||||
|
webscale: true
|
||||||
|
cluster: true
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.serve(httpsWorker);
|
||||||
|
|
||||||
|
function httpsWorker(glx) {
|
||||||
|
// Serves on 80 and 443
|
||||||
|
// Get's SSL certificates magically!
|
||||||
|
|
||||||
|
glx.serveApp(function(req, res) {
|
||||||
|
res.end("Hello, Encrypted World!");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# OLD STUFF BELOW
|
||||||
|
|
||||||
|
# (Preserved for historical reference)
|
||||||
|
|
||||||
| A [Root](https://therootcompany.com) Project
|
| A [Root](https://therootcompany.com) Project
|
||||||
| [greenlock (lib)](https://git.coolaj86.com/coolaj86/greenlock.js)
|
| [greenlock (lib)](https://git.coolaj86.com/coolaj86/greenlock.js)
|
||||||
| [greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js)
|
| [greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js)
|
||||||
|
@ -7,27 +45,24 @@
|
||||||
| [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js)
|
| [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js)
|
||||||
|
|
|
|
||||||
|
|
||||||
|
# greenlock-cluster
|
||||||
|
|
||||||
greenlock-cluster
|
|
||||||
===================
|
|
||||||
(previously letsencrypt-cluster)
|
(previously letsencrypt-cluster)
|
||||||
|
|
||||||
Use automatic letsencrypt with node on multiple cores or even multiple machines.
|
Use automatic letsencrypt with node on multiple cores or even multiple machines.
|
||||||
|
|
||||||
* Take advantage of multi-core computing
|
- Take advantage of multi-core computing
|
||||||
* Process certificates in master
|
- Process certificates in master
|
||||||
* Serve https from multiple workers
|
- Serve https from multiple workers
|
||||||
* Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1)
|
- Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1)
|
||||||
|
|
||||||
Install
|
# Install
|
||||||
=======
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install --save greenlock-cluster@2.x
|
npm install --save greenlock-cluster@2.x
|
||||||
```
|
```
|
||||||
|
|
||||||
Usage
|
# Usage
|
||||||
=====
|
|
||||||
|
|
||||||
In a cluster environment you have some main file that boots your app
|
In a cluster environment you have some main file that boots your app
|
||||||
and then conditionally loads certain code based on whether that fork
|
and then conditionally loads certain code based on whether that fork
|
||||||
|
@ -37,35 +72,34 @@ In such a file you might want to define some of the options that need
|
||||||
to be shared between both the master and the worker, like this:
|
to be shared between both the master and the worker, like this:
|
||||||
|
|
||||||
`boot.js`:
|
`boot.js`:
|
||||||
```javascript
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var cluster = require('cluster');
|
```javascript
|
||||||
var path = require('path');
|
"use strict";
|
||||||
var os = require('os');
|
|
||||||
|
var cluster = require("cluster");
|
||||||
|
var path = require("path");
|
||||||
|
var os = require("os");
|
||||||
|
|
||||||
var main;
|
var main;
|
||||||
var sharedOptions = {
|
var sharedOptions = {
|
||||||
webrootPath: path.join(os.tmpdir(), 'acme-challenge') // /tmp/acme-challenge
|
webrootPath: path.join(os.tmpdir(), "acme-challenge"), // /tmp/acme-challenge
|
||||||
// used by le-challenge-fs, the default plugin
|
// used by le-challenge-fs, the default plugin
|
||||||
|
|
||||||
, renewWithin: 14 * 24 * 60 * 60 * 1000 // 10 days before expiration
|
renewWithin: 14 * 24 * 60 * 60 * 1000, // 10 days before expiration
|
||||||
|
|
||||||
, debug: true
|
debug: true
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cluster.isMaster) {
|
if (cluster.isMaster) {
|
||||||
main = require('./master');
|
main = require("./master");
|
||||||
}
|
} else {
|
||||||
else {
|
main = require("./worker");
|
||||||
main = require('./worker');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main.init(sharedOptions);
|
main.init(sharedOptions);
|
||||||
```
|
```
|
||||||
|
|
||||||
Master
|
## Master
|
||||||
------
|
|
||||||
|
|
||||||
We think it makes the most sense to load greenlock in master.
|
We think it makes the most sense to load greenlock in master.
|
||||||
This can prevent race conditions (see [node-letsencrypt#45](https://github.com/Daplie/node-letsencrypt/issues/45))
|
This can prevent race conditions (see [node-letsencrypt#45](https://github.com/Daplie/node-letsencrypt/issues/45))
|
||||||
|
@ -78,6 +112,7 @@ The master takes **the same arguments** as `node-greenlock` (`challenge`, `store
|
||||||
plus a few extra (`approveDomains`... okay, just one extra):
|
plus a few extra (`approveDomains`... okay, just one extra):
|
||||||
|
|
||||||
`master.js`:
|
`master.js`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -120,75 +155,75 @@ All options are passed directly to `node-greenlock`
|
||||||
(in other works, `leMaster` is a `greenlock` instance),
|
(in other works, `leMaster` is a `greenlock` instance),
|
||||||
but a few are only actually used by `greenlock-cluster`.
|
but a few are only actually used by `greenlock-cluster`.
|
||||||
|
|
||||||
* `leOptions.approveDomains(options, certs, cb)` is special for `greenlock-cluster`, but will probably be included in `node-greenlock` in the future (no API change).
|
- `leOptions.approveDomains(options, certs, cb)` is special for `greenlock-cluster`, but will probably be included in `node-greenlock` in the future (no API change).
|
||||||
|
|
||||||
* `leMaster.addWorker(worker)` is added by `greenlock-cluster` and **must be called** for each new worker.
|
- `leMaster.addWorker(worker)` is added by `greenlock-cluster` and **must be called** for each new worker.
|
||||||
|
|
||||||
Worker
|
## Worker
|
||||||
------
|
|
||||||
|
|
||||||
The worker takes *similar* arguments to `node-greenlock`,
|
The worker takes _similar_ arguments to `node-greenlock`,
|
||||||
but only ones that are useful for determining certificate
|
but only ones that are useful for determining certificate
|
||||||
renewal and for `le.challenge.get`.
|
renewal and for `le.challenge.get`.
|
||||||
|
|
||||||
If you want to a non-default `le.challenge`
|
If you want to a non-default `le.challenge`
|
||||||
|
|
||||||
`worker.js`:
|
`worker.js`:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports.init = function (sharedOpts) {
|
module.exports.init = function(sharedOpts) {
|
||||||
var leWorker = require('greenlock-cluster/worker').create({
|
var leWorker = require("greenlock-cluster/worker").create({
|
||||||
debug: sharedOpts.debug
|
debug: sharedOpts.debug,
|
||||||
|
|
||||||
, renewWithin: sharedOpts.renewWithin
|
renewWithin: sharedOpts.renewWithin,
|
||||||
|
|
||||||
, webrootPath: sharedOpts.webrootPath
|
webrootPath: sharedOpts.webrootPath,
|
||||||
|
|
||||||
// , challenge: require('le-challenge-fs').create({ webrootPath: '...', ... })
|
// , challenge: require('le-challenge-fs').create({ webrootPath: '...', ... })
|
||||||
|
|
||||||
, approveDomains: function (workerOptions, certs, cb) {
|
approveDomains: function(workerOptions, certs, cb) {
|
||||||
// opts = { domains, email, agreeTos, tosUrl }
|
// opts = { domains, email, agreeTos, tosUrl }
|
||||||
// certs = { subject, altnames, expiresAt, issuedAt }
|
// certs = { subject, altnames, expiresAt, issuedAt }
|
||||||
|
|
||||||
var results = {
|
var results = {
|
||||||
domain: workerOptions.domains[0]
|
domain: workerOptions.domains[0],
|
||||||
, options: {
|
options: {
|
||||||
domains: workerOptions.domains
|
domains: workerOptions.domains
|
||||||
|
},
|
||||||
|
certs: certs
|
||||||
|
};
|
||||||
|
|
||||||
|
if (certs) {
|
||||||
|
// modify opts.domains to match the original request
|
||||||
|
// email is not necessary, because the account already exists
|
||||||
|
// this will only fail if the account has become corrupt
|
||||||
|
results.options.domains = certs.altnames;
|
||||||
|
cb(null, results);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is where one would check one's application-specific database:
|
||||||
|
// 1. Lookup the domain to see which email it belongs to
|
||||||
|
// 2. Assign a default email if it isn't in the system
|
||||||
|
// 3. If the email has no le account, `agreeToTerms` will fire unless `agreeTos` is preset
|
||||||
|
|
||||||
|
results.options.email = "john.doe@example.com";
|
||||||
|
results.options.agreeTos = true; // causes agreeToTerms to be skipped
|
||||||
|
cb(null, results);
|
||||||
}
|
}
|
||||||
, certs: certs
|
});
|
||||||
};
|
|
||||||
|
|
||||||
if (certs) {
|
function app(req, res) {
|
||||||
// modify opts.domains to match the original request
|
res.end("Hello, World!");
|
||||||
// email is not necessary, because the account already exists
|
|
||||||
// this will only fail if the account has become corrupt
|
|
||||||
results.options.domains = certs.altnames;
|
|
||||||
cb(null, results);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is where one would check one's application-specific database:
|
|
||||||
// 1. Lookup the domain to see which email it belongs to
|
|
||||||
// 2. Assign a default email if it isn't in the system
|
|
||||||
// 3. If the email has no le account, `agreeToTerms` will fire unless `agreeTos` is preset
|
|
||||||
|
|
||||||
results.options.email = 'john.doe@example.com'
|
|
||||||
results.options.agreeTos = true // causes agreeToTerms to be skipped
|
|
||||||
cb(null, results);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function app(req, res) {
|
var redirectHttps = require("redirect-https")();
|
||||||
res.end("Hello, World!");
|
var plainServer = require("http").createServer(leWorker.middleware(redirectHttps));
|
||||||
}
|
plainServer.listen(80);
|
||||||
|
|
||||||
var redirectHttps = require('redirect-https')();
|
var server = require("https").createServer(leWorker.httpsOptions, leWorker.middleware(app));
|
||||||
var plainServer = require('http').createServer(leWorker.middleware(redirectHttps));
|
server.listen(443);
|
||||||
plainServer.listen(80);
|
|
||||||
|
|
||||||
var server = require('https').createServer(leWorker.httpsOptions, leWorker.middleware(app));
|
|
||||||
server.listen(443);
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -197,16 +232,15 @@ module.exports.init = function (sharedOpts) {
|
||||||
`node-greenlock` is **not used** directly by the worker,
|
`node-greenlock` is **not used** directly by the worker,
|
||||||
but certain options are shared because certain logic is duplicated.
|
but certain options are shared because certain logic is duplicated.
|
||||||
|
|
||||||
* `leOptions.renewWithin` is shared so that the worker knows how earlier to request a new cert
|
- `leOptions.renewWithin` is shared so that the worker knows how earlier to request a new cert
|
||||||
* `leOptions.renewBy` is passed to `le-sni-auto` so that it staggers renewals between `renewWithin` (latest) and `renewBy` (earlier)
|
- `leOptions.renewBy` is passed to `le-sni-auto` so that it staggers renewals between `renewWithin` (latest) and `renewBy` (earlier)
|
||||||
* `leWorker.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath`
|
- `leWorker.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath`
|
||||||
* `leWorker.httpsOptions` has a default localhost certificate and the `SNICallback`.
|
- `leWorker.httpsOptions` has a default localhost certificate and the `SNICallback`.
|
||||||
|
|
||||||
There are a few options that aren't shown in these examples, so if you need to change something
|
There are a few options that aren't shown in these examples, so if you need to change something
|
||||||
that isn't shown here, look at the code (it's not that much) or open an issue.
|
that isn't shown here, look at the code (it's not that much) or open an issue.
|
||||||
|
|
||||||
Message Passing
|
## Message Passing
|
||||||
---------------
|
|
||||||
|
|
||||||
The master and workers will communicate through `process.on('message', fn)`, `process.send({})`,
|
The master and workers will communicate through `process.on('message', fn)`, `process.send({})`,
|
||||||
`worker.on('message', fn)`and `worker.send({})`.
|
`worker.on('message', fn)`and `worker.send({})`.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
greenlock cluster examples
|
## greenlock cluster examples
|
||||||
-------------------
|
|
||||||
|
|
||||||
First you need to change the email address in `examples/worker.js`.
|
First you need to change the email address in `examples/worker.js`.
|
||||||
|
|
||||||
|
|
|
@ -1,35 +1,29 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
var cluster = require('cluster');
|
var cluster = require("cluster");
|
||||||
|
|
||||||
module.exports.init = function (sharedOpts) {
|
module.exports.init = function(sharedOpts) {
|
||||||
var numCores = 2; // // Math.max(2, require('os').cpus().length)
|
var numCores = 2; // // Math.max(2, require('os').cpus().length)
|
||||||
var i;
|
var i;
|
||||||
var master = require('../master').create({
|
var master = require("../master").create({
|
||||||
debug: true
|
debug: true,
|
||||||
|
|
||||||
|
server: "staging",
|
||||||
|
webrootPath: sharedOpts.webrootPath,
|
||||||
|
|
||||||
|
approveDomains: function(masterOptions, certs, cb) {
|
||||||
|
// Depending on your setup it may be more efficient
|
||||||
|
// for you to implement the approveDomains function
|
||||||
|
// in your master or in your workers.
|
||||||
|
//
|
||||||
|
// Since we implement it in the worker (below) in this example
|
||||||
|
// we'll give it an immediate approval here in the master
|
||||||
|
var results = { domain: masterOptions.domain, options: masterOptions, certs: certs };
|
||||||
|
cb(null, results);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
, server: 'staging'
|
for (i = 0; i < numCores; i += 1) {
|
||||||
, webrootPath: sharedOpts.webrootPath
|
master.addWorker(cluster.fork());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
, approveDomains: function (masterOptions, certs, cb) {
|
|
||||||
// Depending on your setup it may be more efficient
|
|
||||||
// for you to implement the approveDomains function
|
|
||||||
// in your master or in your workers.
|
|
||||||
//
|
|
||||||
// Since we implement it in the worker (below) in this example
|
|
||||||
// we'll give it an immediate approval here in the master
|
|
||||||
var results = { domain: masterOptions.domain, options: masterOptions, certs: certs };
|
|
||||||
cb(null, results);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < numCores; i += 1) {
|
|
||||||
master.addWorker(cluster.fork());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,33 +1,27 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
var cluster = require('cluster');
|
var cluster = require("cluster");
|
||||||
var main;
|
var main;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// You'll often see examples where people use cluster
|
// You'll often see examples where people use cluster
|
||||||
// master and worker all in the same file, which is fine,
|
// master and worker all in the same file, which is fine,
|
||||||
// but in order to conserve memory and especially to be
|
// but in order to conserve memory and especially to be
|
||||||
// less confusing, I'm splitting the code into two files
|
// less confusing, I'm splitting the code into two files
|
||||||
if (cluster.isMaster) {
|
if (cluster.isMaster) {
|
||||||
main = require('./master');
|
main = require("./master");
|
||||||
|
} else {
|
||||||
|
main = require("./worker");
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
main = require('./worker');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// this is nothing greenlock-cluster specific
|
// this is nothing greenlock-cluster specific
|
||||||
// I'm just arbitrarily choosing to share some configuration
|
// I'm just arbitrarily choosing to share some configuration
|
||||||
// that I know I'm going to use in both places
|
// that I know I'm going to use in both places
|
||||||
main.init({
|
main.init({
|
||||||
|
// Depending on the strategy, the whole le-challenge-<<strategy>>
|
||||||
|
// could be shared between worker and server, but since I'm just
|
||||||
|
// using using le-challenge-fs (as you'll see), I'm only sharing the webrootPath
|
||||||
|
webrootPath: require("os").tmpdir() + require("path").sep + "acme-challenge",
|
||||||
|
|
||||||
// Depending on the strategy, the whole le-challenge-<<strategy>>
|
// this is used both by node-greenlock (master) and le-sni-auto (worker)
|
||||||
// could be shared between worker and server, but since I'm just
|
renewWithin: 15 * 24 * 60 * 60 * 1000
|
||||||
// using using le-challenge-fs (as you'll see), I'm only sharing the webrootPath
|
|
||||||
webrootPath: require('os').tmpdir() + require('path').sep + 'acme-challenge'
|
|
||||||
|
|
||||||
// this is used both by node-greenlock (master) and le-sni-auto (worker)
|
|
||||||
, renewWithin: 15 * 24 * 60 * 60 * 1000
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
module.exports.init = function (sharedOpts) {
|
module.exports.init = function(sharedOpts) {
|
||||||
var worker = require('../worker').create({
|
var worker = require("../worker").create({
|
||||||
debug: true
|
debug: true,
|
||||||
|
|
||||||
|
// We want both to renew well before the expiration date
|
||||||
|
// and also to stagger the renewals, just a touch
|
||||||
|
// here we specify to renew between 10 and 15 days
|
||||||
|
renewWithin: sharedOpts.renewWithin,
|
||||||
|
renewBy: 10 * 24 * 60 * 60 * 1000, // optional
|
||||||
|
|
||||||
|
webrootPath: sharedOpts.webrootPath,
|
||||||
|
|
||||||
// We want both to renew well before the expiration date
|
/*
|
||||||
// and also to stagger the renewals, just a touch
|
|
||||||
// here we specify to renew between 10 and 15 days
|
|
||||||
, renewWithin: sharedOpts.renewWithin
|
|
||||||
, renewBy: 10 * 24 * 60 * 60 * 1000 // optional
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
, webrootPath: sharedOpts.webrootPath
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
challenge: {
|
challenge: {
|
||||||
get: function (ignored, domain, token, cb) {
|
get: function (ignored, domain, token, cb) {
|
||||||
cb(null, keyAuthorization);
|
cb(null, keyAuthorization);
|
||||||
|
@ -33,55 +27,48 @@ module.exports.init = function (sharedOpts) {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// There are two approval processes:
|
||||||
|
// 1. emails are tied to private keys (accounts) which must agree to the tos url
|
||||||
|
// 2. domains are tied to accounts (and should be verifiable via loopback)
|
||||||
|
approveDomains: function(workerOptions, certs, cb) {
|
||||||
|
// opts = { domains, email, agreeTos, tosUrl }
|
||||||
|
// certs = { subject, altnames, expiresAt, issuedAt }
|
||||||
|
var results = {
|
||||||
|
domain: workerOptions.domains[0],
|
||||||
|
options: {
|
||||||
|
domains: (certs && certs.altnames) || workerOptions.domains,
|
||||||
|
email: "john.doe@example.com",
|
||||||
|
agreeTos: true
|
||||||
|
},
|
||||||
|
certs: certs
|
||||||
|
};
|
||||||
|
|
||||||
// There are two approval processes:
|
// We might want to do a check to make sure that all of the domains
|
||||||
// 1. emails are tied to private keys (accounts) which must agree to the tos url
|
// specified in altnames are still approved to be renewed and have
|
||||||
// 2. domains are tied to accounts (and should be verifiable via loopback)
|
// the correct dns entries, but generally speaking it's probably okay
|
||||||
, approveDomains: function (workerOptions, certs, cb) {
|
// for renewals to be automatic
|
||||||
// opts = { domains, email, agreeTos, tosUrl }
|
if (certs) {
|
||||||
// certs = { subject, altnames, expiresAt, issuedAt }
|
// modify opts.domains to overwrite certs.altnames in renewal
|
||||||
var results = {
|
cb(null, results);
|
||||||
domain: workerOptions.domains[0]
|
return;
|
||||||
, options: {
|
}
|
||||||
domains: certs && certs.altnames || workerOptions.domains
|
|
||||||
, email: 'john.doe@example.com'
|
// This is where we would check our database to make sure that
|
||||||
, agreeTos: true
|
// this user (specified by email address) has agreed to the terms
|
||||||
|
// and do some check that they have access to this domain
|
||||||
|
cb(null, results);
|
||||||
}
|
}
|
||||||
, certs: certs
|
});
|
||||||
};
|
|
||||||
|
|
||||||
|
function app(req, res) {
|
||||||
|
res.end("Hello, World!");
|
||||||
// We might want to do a check to make sure that all of the domains
|
|
||||||
// specified in altnames are still approved to be renewed and have
|
|
||||||
// the correct dns entries, but generally speaking it's probably okay
|
|
||||||
// for renewals to be automatic
|
|
||||||
if (certs) {
|
|
||||||
// modify opts.domains to overwrite certs.altnames in renewal
|
|
||||||
cb(null, results);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This is where we would check our database to make sure that
|
|
||||||
// this user (specified by email address) has agreed to the terms
|
|
||||||
// and do some check that they have access to this domain
|
|
||||||
cb(null, results);
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function app(req, res) {
|
// worker.handleAcmeOrRedirectToHttps()
|
||||||
res.end("Hello, World!");
|
// worker.handleAcmeOrUse(app)
|
||||||
}
|
var redirectHttps = require("redirect-https")();
|
||||||
|
var plainServer = require("http").createServer(worker.middleware(redirectHttps));
|
||||||
|
var server = require("https").createServer(worker.httpsOptions, worker.middleware(app));
|
||||||
// worker.handleAcmeOrRedirectToHttps()
|
plainServer.listen(80);
|
||||||
// worker.handleAcmeOrUse(app)
|
server.listen(443);
|
||||||
var redirectHttps = require('redirect-https')();
|
|
||||||
var plainServer = require('http').createServer(worker.middleware(redirectHttps));
|
|
||||||
var server = require('https').createServer(worker.httpsOptions, worker.middleware(app));
|
|
||||||
plainServer.listen(80);
|
|
||||||
server.listen(443);
|
|
||||||
};
|
};
|
||||||
|
|
13
index.js
13
index.js
|
@ -1,12 +1,3 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
console.error("");
|
module.exports = require("@root/greenlock-express");
|
||||||
console.error("One does not simply require('greenlock-cluster');");
|
|
||||||
console.error("");
|
|
||||||
console.error("Usage:");
|
|
||||||
console.error("\trequire('greenlock-cluster/master').create({ ... });");
|
|
||||||
console.error("\trequire('greenlock-cluster/worker').create({ ... });");
|
|
||||||
console.error("");
|
|
||||||
console.error("");
|
|
||||||
|
|
||||||
process.exit(1);
|
|
||||||
|
|
136
master.js
136
master.js
|
@ -1,58 +1,60 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
// opts.addWorker(worker)
|
// opts.addWorker(worker)
|
||||||
// opts.approveDomains(options, certs, cb)
|
// opts.approveDomains(options, certs, cb)
|
||||||
module.exports.create = function (opts) {
|
module.exports.create = function(opts) {
|
||||||
opts = opts || { };
|
opts = opts || {};
|
||||||
opts._workers = [];
|
opts._workers = [];
|
||||||
opts.webrootPath = opts.webrootPath || require('os').tmpdir() + require('path').sep + 'acme-challenge';
|
opts.webrootPath = opts.webrootPath || require("os").tmpdir() + require("path").sep + "acme-challenge";
|
||||||
if (!opts.greenlock) { opts.greenlock = require('greenlock').create(opts); }
|
if (!opts.greenlock) {
|
||||||
if ('function' !== typeof opts.approveDomains) {
|
opts.greenlock = require("greenlock").create(opts);
|
||||||
throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates");
|
}
|
||||||
}
|
if ("function" !== typeof opts.approveDomains) {
|
||||||
|
throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates");
|
||||||
function log(debug) {
|
|
||||||
if (!debug) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = Array.prototype.slice.call(arguments);
|
function log(debug) {
|
||||||
args.shift();
|
if (!debug) {
|
||||||
args.unshift("[le/lib/core.js]");
|
return;
|
||||||
console.log.apply(console, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
opts.addWorker = function (worker) {
|
|
||||||
opts._workers.push(worker);
|
|
||||||
|
|
||||||
worker.on('online', function () {
|
|
||||||
log(opts.debug, 'worker is up');
|
|
||||||
});
|
|
||||||
|
|
||||||
worker.on('message', function (msg) {
|
|
||||||
log(opts.debug, 'Message from worker ' + worker.id);
|
|
||||||
if ('LE_REQUEST' !== (msg && msg.type)) {
|
|
||||||
log(opts.debug, 'Ignoring irrelevant message');
|
|
||||||
log(opts.debug, msg);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log(opts.debug, 'about to approveDomains');
|
|
||||||
opts.approveDomains(msg.options, msg.certs, function (err, results) {
|
|
||||||
if (err) {
|
|
||||||
log(opts.debug, 'Approval got ERROR', err.stack || err);
|
|
||||||
worker.send({
|
|
||||||
type: 'LE_RESPONSE'
|
|
||||||
, domain: msg.domain
|
|
||||||
, error: { message: err.message, code: err.code, stack: err.stack }
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var promise;
|
var args = Array.prototype.slice.call(arguments);
|
||||||
|
args.shift();
|
||||||
|
args.unshift("[le/lib/core.js]");
|
||||||
|
console.log.apply(console, args);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
opts.addWorker = function(worker) {
|
||||||
/*
|
opts._workers.push(worker);
|
||||||
|
|
||||||
|
worker.on("online", function() {
|
||||||
|
log(opts.debug, "worker is up");
|
||||||
|
});
|
||||||
|
|
||||||
|
worker.on("message", function(msg) {
|
||||||
|
log(opts.debug, "Message from worker " + worker.id);
|
||||||
|
if ("LE_REQUEST" !== (msg && msg.type)) {
|
||||||
|
log(opts.debug, "Ignoring irrelevant message");
|
||||||
|
log(opts.debug, msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(opts.debug, "about to approveDomains");
|
||||||
|
opts.approveDomains(msg.options, msg.certs, function(err, results) {
|
||||||
|
if (err) {
|
||||||
|
log(opts.debug, "Approval got ERROR", err.stack || err);
|
||||||
|
worker.send({
|
||||||
|
type: "LE_RESPONSE",
|
||||||
|
domain: msg.domain,
|
||||||
|
error: { message: err.message, code: err.code, stack: err.stack }
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var promise;
|
||||||
|
|
||||||
|
//
|
||||||
|
/*
|
||||||
var certs = require('localhost.example.com-certificates').merge({
|
var certs = require('localhost.example.com-certificates').merge({
|
||||||
subject: msg.domain
|
subject: msg.domain
|
||||||
, altnames: [ msg.domain ]
|
, altnames: [ msg.domain ]
|
||||||
|
@ -66,26 +68,28 @@ module.exports.create = function (opts) {
|
||||||
return;
|
return;
|
||||||
// */
|
// */
|
||||||
|
|
||||||
if (results.certs) {
|
if (results.certs) {
|
||||||
promise = opts.greenlock.renew(results.options, results.certs);
|
promise = opts.greenlock.renew(results.options, results.certs);
|
||||||
}
|
} else {
|
||||||
else {
|
promise = opts.greenlock.register(results.options);
|
||||||
promise = opts.greenlock.register(results.options);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
promise.then(function (certs) {
|
promise.then(
|
||||||
log(opts.debug, 'Approval got certs', certs);
|
function(certs) {
|
||||||
// certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain };
|
log(opts.debug, "Approval got certs", certs);
|
||||||
opts._workers.forEach(function (w) {
|
// certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain };
|
||||||
w.send({ type: 'LE_RESPONSE', domain: msg.domain, certs: certs });
|
opts._workers.forEach(function(w) {
|
||||||
});
|
w.send({ type: "LE_RESPONSE", domain: msg.domain, certs: certs });
|
||||||
}, function (err) {
|
});
|
||||||
log(opts.debug, 'Approval got ERROR', err.stack || err);
|
},
|
||||||
worker.send({ type: 'LE_RESPONSE', domain: msg.domain, error: err });
|
function(err) {
|
||||||
|
log(opts.debug, "Approval got ERROR", err.stack || err);
|
||||||
|
worker.send({ type: "LE_RESPONSE", domain: msg.domain, error: err });
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return opts;
|
return opts;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
{
|
||||||
|
"name": "greenlock-cluster",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@root/acme": {
|
||||||
|
"version": "3.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/acme/-/acme-3.0.8.tgz",
|
||||||
|
"integrity": "sha512-VmBvLvWdCDkolkanI9Dzm1ouSWPaAa2eCCwcDZcVQbWoNiUIOqbbd57fcMA/gZxLyuJPStD2WXFuEuSMPDxcww==",
|
||||||
|
"requires": {
|
||||||
|
"@root/encoding": "^1.0.1",
|
||||||
|
"@root/keypairs": "^0.9.0",
|
||||||
|
"@root/pem": "^1.0.4",
|
||||||
|
"@root/request": "^1.3.11",
|
||||||
|
"@root/x509": "^0.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/asn1": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/asn1/-/asn1-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-0lfZNuOULKJDJmdIkP8V9RnbV3XaK6PAHD3swnFy4tZwtlMDzLKoM/dfNad7ut8Hu3r91wy9uK0WA/9zym5mig==",
|
||||||
|
"requires": {
|
||||||
|
"@root/encoding": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/csr": {
|
||||||
|
"version": "0.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/csr/-/csr-0.8.1.tgz",
|
||||||
|
"integrity": "sha512-hKl0VuE549TK6SnS2Yn9nRvKbFZXn/oAg+dZJU/tlKl/f/0yRXeuUzf8akg3JjtJq+9E592zDqeXZ7yyrg8fSQ==",
|
||||||
|
"requires": {
|
||||||
|
"@root/asn1": "^1.0.0",
|
||||||
|
"@root/pem": "^1.0.4",
|
||||||
|
"@root/x509": "^0.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/encoding": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/encoding/-/encoding-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-OaEub02ufoU038gy6bsNHQOjIn8nUjGiLcaRmJ40IUykneJkIW5fxDqKxQx48cszuNflYldsJLPPXCrGfHs8yQ=="
|
||||||
|
},
|
||||||
|
"@root/greenlock": {
|
||||||
|
"version": "3.0.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/greenlock/-/greenlock-3.0.25.tgz",
|
||||||
|
"integrity": "sha512-VC8H9MTkbqxlB2LGntmcq5cstkE0TdZLvxm25SO5i7c6abJBVMQafhTD415OXwoGimnmWTn6SZ93Fj73d9QX/w==",
|
||||||
|
"requires": {
|
||||||
|
"@root/acme": "^3.0.8",
|
||||||
|
"@root/csr": "^0.8.1",
|
||||||
|
"@root/keypairs": "^0.9.0",
|
||||||
|
"@root/mkdirp": "^1.0.0",
|
||||||
|
"@root/request": "^1.3.10",
|
||||||
|
"acme-http-01-standalone": "^3.0.5",
|
||||||
|
"cert-info": "^1.5.1",
|
||||||
|
"greenlock-manager-fs": "^3.0.1",
|
||||||
|
"greenlock-store-fs": "^3.2.0",
|
||||||
|
"safe-replace": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/greenlock-express": {
|
||||||
|
"version": "3.0.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/greenlock-express/-/greenlock-express-3.0.13.tgz",
|
||||||
|
"integrity": "sha512-SgFsP4rBDPRBp52yqb8kONw7ZCkgyYrBFJLg4xhfIMbsMct4dfqB+N5eJbeF/exJh4+BHM7tppvf31Xuz6EO2Q==",
|
||||||
|
"requires": {
|
||||||
|
"@root/greenlock": "^3.0.25",
|
||||||
|
"redirect-https": "^1.1.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/keypairs": {
|
||||||
|
"version": "0.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/keypairs/-/keypairs-0.9.0.tgz",
|
||||||
|
"integrity": "sha512-NXE2L9Gv7r3iC4kB/gTPZE1vO9Ox/p14zDzAJ5cGpTpytbWOlWF7QoHSJbtVX4H7mRG/Hp7HR3jWdWdb2xaaXg==",
|
||||||
|
"requires": {
|
||||||
|
"@root/encoding": "^1.0.1",
|
||||||
|
"@root/pem": "^1.0.4",
|
||||||
|
"@root/x509": "^0.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@root/mkdirp": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
|
||||||
|
},
|
||||||
|
"@root/pem": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/pem/-/pem-1.0.4.tgz",
|
||||||
|
"integrity": "sha512-rEUDiUsHtild8GfIjFE9wXtcVxeS+ehCJQBwbQQ3IVfORKHK93CFnRtkr69R75lZFjcmKYVc+AXDB+AeRFOULA=="
|
||||||
|
},
|
||||||
|
"@root/request": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/request/-/request-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-J8FM4+SJuc7WRC+Jz17m+VT2lgI7HtatHhxN1F2ck5aIKUAxJEaR4u/gLBsgT60mVHevKCjKN0O8115UtJjwLw=="
|
||||||
|
},
|
||||||
|
"@root/x509": {
|
||||||
|
"version": "0.7.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@root/x509/-/x509-0.7.2.tgz",
|
||||||
|
"integrity": "sha512-ENq3LGYORK5NiMFHEVeNMt+fTXaC7DTS6sQXoqV+dFdfT0vmiL5cDLjaXQhaklJQq0NiwicZegzJRl1ZOTp3WQ==",
|
||||||
|
"requires": {
|
||||||
|
"@root/asn1": "^1.0.0",
|
||||||
|
"@root/encoding": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"acme-http-01-standalone": {
|
||||||
|
"version": "3.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/acme-http-01-standalone/-/acme-http-01-standalone-3.0.5.tgz",
|
||||||
|
"integrity": "sha512-W4GfK+39GZ+u0mvxRVUcVFCG6gposfzEnSBF20T/NUwWAKG59wQT1dUbS1NixRIAsRuhpGc4Jx659cErFQH0Pg=="
|
||||||
|
},
|
||||||
|
"cert-info": {
|
||||||
|
"version": "1.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cert-info/-/cert-info-1.5.1.tgz",
|
||||||
|
"integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ=="
|
||||||
|
},
|
||||||
|
"escape-html": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
|
||||||
|
},
|
||||||
|
"greenlock-manager-fs": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/greenlock-manager-fs/-/greenlock-manager-fs-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vZfGFq1TTKxaAqdGDUwNservrNzXx0xCwT/ovG/N378GrhS+U5S8B8LUlNtQU7Fdw6RToMiBcm22OOxSrvZ2zw==",
|
||||||
|
"requires": {
|
||||||
|
"@root/mkdirp": "^1.0.0",
|
||||||
|
"safe-replace": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"greenlock-store-fs": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/greenlock-store-fs/-/greenlock-store-fs-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-zqcPnF+173oYq5qU7FoGtuqeG8dmmvAiSnz98kEHAHyvgRF9pE1T0MM0AuqDdj45I3kXlCj2gZBwutnRi37J3g==",
|
||||||
|
"requires": {
|
||||||
|
"@root/mkdirp": "^1.0.0",
|
||||||
|
"safe-replace": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"redirect-https": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/redirect-https/-/redirect-https-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-9GzwI/+Cqw3jlSg0CW6TgBQbhiVhkHSDvW8wjgRQ9IK34wtxS71YJiQeazSCSEqbvowHCJuQZgmQFl1xUHKEgg==",
|
||||||
|
"requires": {
|
||||||
|
"escape-html": "^1.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"safe-replace": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
80
package.json
80
package.json
|
@ -1,44 +1,40 @@
|
||||||
{
|
{
|
||||||
"name": "greenlock-cluster",
|
"name": "greenlock-cluster",
|
||||||
"version": "2.1.0",
|
"version": "3.0.0",
|
||||||
"description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines",
|
"description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
"example": "examples"
|
"example": "examples"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"le-sni-auto": "^2.0.1",
|
"@root/greenlock-express": "^3.0.13"
|
||||||
"greenlock": "^2.0.4",
|
},
|
||||||
"redirect-https": "^1.1.0"
|
"devDependencies": {},
|
||||||
},
|
"scripts": {},
|
||||||
"devDependencies": {},
|
"repository": {
|
||||||
"scripts": {
|
"type": "git",
|
||||||
"test": "node examples/serve.js"
|
"url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git"
|
||||||
},
|
},
|
||||||
"repository": {
|
"keywords": [
|
||||||
"type": "git",
|
"cluster",
|
||||||
"url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git"
|
"acme",
|
||||||
},
|
"le",
|
||||||
"keywords": [
|
"multi-core",
|
||||||
"cluster",
|
"cloud",
|
||||||
"acme",
|
"scale",
|
||||||
"le",
|
"free",
|
||||||
"multi-core",
|
"ssl",
|
||||||
"cloud",
|
"https",
|
||||||
"scale",
|
"tls",
|
||||||
"free",
|
"letsencrypt",
|
||||||
"ssl",
|
"node",
|
||||||
"https",
|
"greenlock",
|
||||||
"tls",
|
"node.js"
|
||||||
"letsencrypt",
|
],
|
||||||
"node",
|
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
||||||
"greenlock",
|
"license": "MPL-2.0",
|
||||||
"node.js"
|
"bugs": {
|
||||||
],
|
"url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues"
|
||||||
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
|
},
|
||||||
"license": "(MIT OR Apache-2.0)",
|
"homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js"
|
||||||
"bugs": {
|
|
||||||
"url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues"
|
|
||||||
},
|
|
||||||
"homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js"
|
|
||||||
}
|
}
|
||||||
|
|
130
worker.js
130
worker.js
|
@ -1,88 +1,78 @@
|
||||||
'use strict';
|
"use strict";
|
||||||
|
|
||||||
function log(debug) {
|
function log(debug) {
|
||||||
if (!debug) {
|
if (!debug) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
args.shift();
|
args.shift();
|
||||||
args.unshift("[le/lib/core.js]");
|
args.unshift("[le/lib/core.js]");
|
||||||
console.log.apply(console, args);
|
console.log.apply(console, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports.create = function(opts) {
|
||||||
|
// if another worker updates the certs,
|
||||||
module.exports.create = function (opts) {
|
// receive a copy from master here as well
|
||||||
|
// and update the sni cache manually
|
||||||
// if another worker updates the certs,
|
process.on("message", function(msg) {
|
||||||
// receive a copy from master here as well
|
if ("LE_RESPONSE" === msg.type && msg.certs) {
|
||||||
// and update the sni cache manually
|
opts.sni.cacheCerts(msg.certs);
|
||||||
process.on('message', function (msg) {
|
|
||||||
if ('LE_RESPONSE' === msg.type && msg.certs) {
|
|
||||||
opts.sni.cacheCerts(msg.certs);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
opts.sni = require('le-sni-auto').create({
|
|
||||||
renewWithin: opts.renewWithin || (10 * 24 * 60 * 60 * 1000)
|
|
||||||
, renewBy: opts.renewBy || (5 * 24 * 60 * 60 * 1000)
|
|
||||||
, getCertificates: function (domain, certs, cb) {
|
|
||||||
var workerOptions = { domains: [ domain ] };
|
|
||||||
opts.approveDomains(workerOptions, certs, function (_err, results) {
|
|
||||||
if (_err) {
|
|
||||||
cb(_err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
process.send({ type: 'LE_REQUEST', domain: domain, options: results.options, certs: results.certs });
|
opts.sni = require("le-sni-auto").create({
|
||||||
|
renewWithin: opts.renewWithin || 10 * 24 * 60 * 60 * 1000,
|
||||||
|
renewBy: opts.renewBy || 5 * 24 * 60 * 60 * 1000,
|
||||||
|
getCertificates: function(domain, certs, cb) {
|
||||||
|
var workerOptions = { domains: [domain] };
|
||||||
|
opts.approveDomains(workerOptions, certs, function(_err, results) {
|
||||||
|
if (_err) {
|
||||||
|
cb(_err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
process.on('message', function (msg) {
|
process.send({ type: "LE_REQUEST", domain: domain, options: results.options, certs: results.certs });
|
||||||
var err = new Error("___MESSAGE___");
|
|
||||||
|
|
||||||
log(opts.debug, 'Message from master');
|
process.on("message", function(msg) {
|
||||||
log(opts.debug, msg);
|
var err = new Error("___MESSAGE___");
|
||||||
|
|
||||||
if (msg.domain !== domain) {
|
log(opts.debug, "Message from master");
|
||||||
return;
|
log(opts.debug, msg);
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.error) {
|
if (msg.domain !== domain) {
|
||||||
err.message = msg.error.message || "unknown error sent from cluster master to worker";
|
return;
|
||||||
err.stack.replace("___MESSAGE___", err.message);
|
}
|
||||||
err = {
|
|
||||||
message: err.message
|
|
||||||
, stack: err.stack
|
|
||||||
, data: { options: workerOptions, certs: certs }
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
err = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(err, msg.certs);
|
if (msg.error) {
|
||||||
});
|
err.message = msg.error.message || "unknown error sent from cluster master to worker";
|
||||||
});
|
err.stack.replace("___MESSAGE___", err.message);
|
||||||
}
|
err = {
|
||||||
});
|
message: err.message,
|
||||||
|
stack: err.stack,
|
||||||
|
data: { options: workerOptions, certs: certs }
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
err = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(err, msg.certs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
opts.httpsOptions = { SNICallback: opts.sni.sniCallback };
|
||||||
|
|
||||||
opts.httpsOptions = { SNICallback: opts.sni.sniCallback };
|
opts.challenge = {
|
||||||
|
get:
|
||||||
|
opts.getChallenge ||
|
||||||
|
(opts.challenge && opts.challenge.get) ||
|
||||||
|
require("le-challenge-fs").create({ webrootPath: opts.webrootPath }).get
|
||||||
|
};
|
||||||
|
|
||||||
|
// opts.challenge.get, opts.acmeChallengePrefix
|
||||||
|
opts.middleware = require("greenlock/lib/middleware").create(opts);
|
||||||
|
|
||||||
|
return opts;
|
||||||
opts.challenge = {
|
|
||||||
get: opts.getChallenge
|
|
||||||
|| (opts.challenge && opts.challenge.get)
|
|
||||||
|| require('le-challenge-fs').create({ webrootPath: opts.webrootPath }).get
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// opts.challenge.get, opts.acmeChallengePrefix
|
|
||||||
opts.middleware = require('greenlock/lib/middleware').create(opts);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return opts;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue