Compare commits
	
		
			No commits in common. "v2.0.6" and "master" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								.prettierrc
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| { | ||||
|   "bracketSpacing": true, | ||||
|   "printWidth": 120, | ||||
|   "tabWidth": 4, | ||||
|   "trailingComma": "none", | ||||
|   "useTabs": false | ||||
| } | ||||
							
								
								
									
										154
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										154
									
								
								README.md
									
									
									
									
									
								
							| @ -1,47 +1,68 @@ | ||||
| <!-- BANNER_TPL_BEGIN --> | ||||
| # Replaced: Use Greenlock Express v3 | ||||
| 
 | ||||
| About Daplie: We're taking back the Internet! | ||||
| -------------- | ||||
| See https://git.rootprojects.org/root/greenlock-express.js | ||||
| 
 | ||||
| Down with Google, Apple, and Facebook! | ||||
| ```js | ||||
| "use strict"; | ||||
| 
 | ||||
| We're re-decentralizing the web and making it read-write again - one home cloud system at a time. | ||||
| var pkg = require("./package.json"); | ||||
| require("greenlock-express") | ||||
|     .init(function getConfig() { | ||||
|         // Greenlock Config | ||||
| 
 | ||||
| Tired of serving the Empire? Come join the Rebel Alliance: | ||||
|         return { | ||||
|             package: { name: pkg.name, version: pkg.version }, | ||||
|             maintainerEmail: pkg.author, | ||||
| 
 | ||||
| <a href="mailto:jobs@daplie.com">jobs@daplie.com</a> | [Invest in Daplie on Wefunder](https://daplie.com/invest/) | [Pre-order Cloud](https://daplie.com/preorder/), The World's First Home Server for Everyone | ||||
|             // put cluster on full throttle! | ||||
|             cloudnative: true | ||||
|             webscale: true | ||||
|             cluster: true | ||||
|         }; | ||||
|     }) | ||||
|     .serve(httpsWorker); | ||||
| 
 | ||||
| <!-- BANNER_TPL_END --> | ||||
| function httpsWorker(glx) { | ||||
|     // Serves on 80 and 443 | ||||
|     // Get's SSL certificates magically! | ||||
| 
 | ||||
| [](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||||
|     glx.serveApp(function(req, res) { | ||||
|         res.end("Hello, Encrypted World!"); | ||||
|     }); | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| | [greenlock (lib)](https://git.daplie.com/Daplie/node-greenlock) | ||||
| | [greenlock-cli](https://git.daplie.com/Daplie/greenlock-cli) | ||||
| | [greenlock-express](https://git.daplie.com/Daplie/greenlock-express) | ||||
| # OLD STUFF BELOW | ||||
| 
 | ||||
| # (Preserved for historical reference) | ||||
| 
 | ||||
| | A [Root](https://therootcompany.com) Project | ||||
| | [greenlock (lib)](https://git.coolaj86.com/coolaj86/greenlock.js) | ||||
| | [greenlock-cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js) | ||||
| | [greenlock-express](https://git.coolaj86.com/coolaj86/greenlock-express.js) | ||||
| | **greenlock-cluster** | ||||
| | [greenlock-koa](https://git.daplie.com/Daplie/greenlock-koa) | ||||
| | [greenlock-hapi](https://git.daplie.com/Daplie/greenlock-hapi) | ||||
| | [greenlock-koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js) | ||||
| | [greenlock-hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js) | ||||
| | | ||||
| 
 | ||||
| greenlock-cluster (letsencrypt-cluster) | ||||
| =================== | ||||
| # greenlock-cluster | ||||
| 
 | ||||
| (previously letsencrypt-cluster) | ||||
| 
 | ||||
| Use automatic letsencrypt with node on multiple cores or even multiple machines. | ||||
| 
 | ||||
| * Take advantage of multi-core computing | ||||
| * Process certificates in master | ||||
| * Serve https from multiple workers | ||||
| * Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) | ||||
| -   Take advantage of multi-core computing | ||||
| -   Process certificates in master | ||||
| -   Serve https from multiple workers | ||||
| -   Can work with any clustering strategy [#1](https://github.com/Daplie/letsencrypt-cluster/issues/1) | ||||
| 
 | ||||
| Install | ||||
| ======= | ||||
| # Install | ||||
| 
 | ||||
| ```bash | ||||
| npm install --save greenlock-cluster@2.x | ||||
| ``` | ||||
| 
 | ||||
| Usage | ||||
| ===== | ||||
| # Usage | ||||
| 
 | ||||
| In a cluster environment you have some main file that boots your app | ||||
| and then conditionally loads certain code based on whether that fork | ||||
| @ -51,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: | ||||
| 
 | ||||
| `boot.js`: | ||||
| ```javascript | ||||
| 'use strict'; | ||||
| 
 | ||||
| var cluster = require('cluster'); | ||||
| var path = require('path'); | ||||
| var os = require('os'); | ||||
| ```javascript | ||||
| "use strict"; | ||||
| 
 | ||||
| var cluster = require("cluster"); | ||||
| var path = require("path"); | ||||
| var os = require("os"); | ||||
| 
 | ||||
| var main; | ||||
| 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 | ||||
| 
 | ||||
| , renewWithin: 10 * 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) { | ||||
|   main = require('./master'); | ||||
| } | ||||
| else { | ||||
|   main = require('./worker'); | ||||
|     main = require("./master"); | ||||
| } else { | ||||
|     main = require("./worker"); | ||||
| } | ||||
| 
 | ||||
| main.init(sharedOptions); | ||||
| ``` | ||||
| 
 | ||||
| Master | ||||
| ------ | ||||
| ## 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)) | ||||
| @ -92,6 +112,7 @@ The master takes **the same arguments** as `node-greenlock` (`challenge`, `store | ||||
| plus a few extra (`approveDomains`... okay, just one extra): | ||||
| 
 | ||||
| `master.js`: | ||||
| 
 | ||||
| ```javascript | ||||
| 'use strict'; | ||||
| 
 | ||||
| @ -102,7 +123,9 @@ module.exports.init = function (sharedOpts) { | ||||
|   var leMaster = require('greenlock-cluster/master').create({ | ||||
|     debug: sharedOpts.debug | ||||
| 
 | ||||
|   , server: 'staging'                                                       // CHANGE TO PRODUCTION | ||||
|     // You MUST change this to 'https://acme-v02.api.letsencrypt.org/directory' in production | ||||
|     server: 'https://acme-staging-v02.api.letsencrypt.org/directory' | ||||
|   , version: 'draft-11' // Let's Encrypt v2 | ||||
| 
 | ||||
|   , renewWithin: sharedOpts.renewWithin | ||||
| 
 | ||||
| @ -132,43 +155,43 @@ All options are passed directly to `node-greenlock` | ||||
| (in other works, `leMaster` is a `greenlock` instance), | ||||
| 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 | ||||
| renewal and for `le.challenge.get`. | ||||
| 
 | ||||
| If you want to a non-default `le.challenge` | ||||
| 
 | ||||
| `worker.js`: | ||||
| 
 | ||||
| ```javascript | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
| 
 | ||||
| module.exports.init = function (sharedOpts) { | ||||
|   var leWorker = require('greenlock-cluster/worker').create({ | ||||
|     debug: sharedOpts.debug | ||||
| module.exports.init = function(sharedOpts) { | ||||
|     var leWorker = require("greenlock-cluster/worker").create({ | ||||
|         debug: sharedOpts.debug, | ||||
| 
 | ||||
|   , renewWithin: sharedOpts.renewWithin | ||||
|         renewWithin: sharedOpts.renewWithin, | ||||
| 
 | ||||
|   , webrootPath: sharedOpts.webrootPath | ||||
|         webrootPath: sharedOpts.webrootPath, | ||||
| 
 | ||||
|         // , challenge: require('le-challenge-fs').create({ webrootPath: '...', ... }) | ||||
| 
 | ||||
|   , approveDomains: function (workerOptions, certs, cb) { | ||||
|         approveDomains: function(workerOptions, certs, cb) { | ||||
|             // opts = { domains, email, agreeTos, tosUrl } | ||||
|             // certs = { subject, altnames, expiresAt, issuedAt } | ||||
| 
 | ||||
|             var results = { | ||||
|         domain: workerOptions.domains[0] | ||||
|       , options: { | ||||
|                 domain: workerOptions.domains[0], | ||||
|                 options: { | ||||
|                     domains: workerOptions.domains | ||||
|         } | ||||
|       , certs: certs | ||||
|                 }, | ||||
|                 certs: certs | ||||
|             }; | ||||
| 
 | ||||
|             if (certs) { | ||||
| @ -185,8 +208,8 @@ module.exports.init = function (sharedOpts) { | ||||
|             //   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 | ||||
|             results.options.email = "john.doe@example.com"; | ||||
|             results.options.agreeTos = true; // causes agreeToTerms to be skipped | ||||
|             cb(null, results); | ||||
|         } | ||||
|     }); | ||||
| @ -195,11 +218,11 @@ module.exports.init = function (sharedOpts) { | ||||
|         res.end("Hello, World!"); | ||||
|     } | ||||
| 
 | ||||
|   var redirectHttps = require('redirect-https')(); | ||||
|   var plainServer = require('http').createServer(leWorker.middleware(redirectHttps)); | ||||
|     var redirectHttps = require("redirect-https")(); | ||||
|     var plainServer = require("http").createServer(leWorker.middleware(redirectHttps)); | ||||
|     plainServer.listen(80); | ||||
| 
 | ||||
|   var server = require('https').createServer(leWorker.httpsOptions, leWorker.middleware(app)); | ||||
|     var server = require("https").createServer(leWorker.httpsOptions, leWorker.middleware(app)); | ||||
|     server.listen(443); | ||||
| }; | ||||
| ``` | ||||
| @ -209,16 +232,15 @@ module.exports.init = function (sharedOpts) { | ||||
| `node-greenlock` is **not used** directly by the worker, | ||||
| 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.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.httpsOptions` has a default localhost certificate and the `SNICallback`. | ||||
| -   `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) | ||||
| -   `leWorker.middleware(nextApp)` uses `greenlock/middleware` for GET-ing `http-01`, hence `sharedOptions.webrootPath` | ||||
| -   `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 | ||||
| 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({})`, | ||||
| `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`. | ||||
| 
 | ||||
|  | ||||
| @ -1,21 +1,17 @@ | ||||
| '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 i; | ||||
|   var master = require('../master').create({ | ||||
|     debug: true | ||||
|     var master = require("../master").create({ | ||||
|         debug: true, | ||||
| 
 | ||||
|         server: "staging", | ||||
|         webrootPath: sharedOpts.webrootPath, | ||||
| 
 | ||||
| 
 | ||||
|   , server: 'staging' | ||||
|   , webrootPath: sharedOpts.webrootPath | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   , approveDomains: function (masterOptions, certs, cb) { | ||||
|         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.
 | ||||
| @ -27,8 +23,6 @@ module.exports.init = function (sharedOpts) { | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     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; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // You'll often see examples where people use cluster
 | ||||
| // master and worker all in the same file, which is fine,
 | ||||
| // but in order to conserve memory and especially to be
 | ||||
| // less confusing, I'm splitting the code into two files
 | ||||
| if (cluster.isMaster) { | ||||
|   main = require('./master'); | ||||
|     main = require("./master"); | ||||
| } else { | ||||
|     main = require("./worker"); | ||||
| } | ||||
| else { | ||||
|   main = require('./worker'); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| // this is nothing greenlock-cluster specific
 | ||||
| // I'm just arbitrarily choosing to share some configuration
 | ||||
| // that I know I'm going to use in both places
 | ||||
| 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' | ||||
|     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 | ||||
|     renewWithin: 15 * 24 * 60 * 60 * 1000 | ||||
| }); | ||||
|  | ||||
| @ -1,22 +1,16 @@ | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.init = function (sharedOpts) { | ||||
|   var worker = require('../worker').create({ | ||||
|     debug: true | ||||
| 
 | ||||
| "use strict"; | ||||
| 
 | ||||
| module.exports.init = function(sharedOpts) { | ||||
|     var worker = require("../worker").create({ | ||||
|         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 | ||||
| 
 | ||||
|         renewWithin: sharedOpts.renewWithin, | ||||
|         renewBy: 10 * 24 * 60 * 60 * 1000, // optional
 | ||||
| 
 | ||||
|         webrootPath: sharedOpts.webrootPath, | ||||
| 
 | ||||
|         /* | ||||
|     challenge: { | ||||
| @ -33,25 +27,22 @@ 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) { | ||||
|         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 | ||||
|                 domain: workerOptions.domains[0], | ||||
|                 options: { | ||||
|                     domains: (certs && certs.altnames) || workerOptions.domains, | ||||
|                     email: "john.doe@example.com", | ||||
|                     agreeTos: true | ||||
|                 }, | ||||
|                 certs: certs | ||||
|             }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|             // 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
 | ||||
| @ -62,9 +53,6 @@ module.exports.init = function (sharedOpts) { | ||||
|                 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
 | ||||
| @ -76,12 +64,11 @@ module.exports.init = function (sharedOpts) { | ||||
|         res.end("Hello, World!"); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     // worker.handleAcmeOrRedirectToHttps()
 | ||||
|     // 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)); | ||||
|     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(""); | ||||
| 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); | ||||
| module.exports = require("@root/greenlock-express"); | ||||
|  | ||||
							
								
								
									
										64
									
								
								master.js
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								master.js
									
									
									
									
									
								
							| @ -1,13 +1,15 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
| 
 | ||||
| // opts.addWorker(worker)
 | ||||
| // opts.approveDomains(options, certs, cb)
 | ||||
| module.exports.create = function (opts) { | ||||
|   opts = opts || { }; | ||||
| module.exports.create = function(opts) { | ||||
|     opts = opts || {}; | ||||
|     opts._workers = []; | ||||
|   opts.webrootPath = opts.webrootPath || require('os').tmpdir() + require('path').sep + 'acme-challenge'; | ||||
|   if (!opts.greenlock) { opts.greenlock = require('greenlock').create(opts); } | ||||
|   if ('function' !== typeof opts.approveDomains) { | ||||
|     opts.webrootPath = opts.webrootPath || require("os").tmpdir() + require("path").sep + "acme-challenge"; | ||||
|     if (!opts.greenlock) { | ||||
|         opts.greenlock = require("greenlock").create(opts); | ||||
|     } | ||||
|     if ("function" !== typeof opts.approveDomains) { | ||||
|         throw new Error("You must provide opts.approveDomains(domain, certs, callback) to approve certificates"); | ||||
|     } | ||||
| 
 | ||||
| @ -22,29 +24,29 @@ module.exports.create = function (opts) { | ||||
|         console.log.apply(console, args); | ||||
|     } | ||||
| 
 | ||||
|   opts.addWorker = function (worker) { | ||||
|     opts.addWorker = function(worker) { | ||||
|         opts._workers.push(worker); | ||||
| 
 | ||||
|     worker.on('online', function () { | ||||
|       log(opts.debug, 'worker is up'); | ||||
|         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'); | ||||
|         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) { | ||||
|             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); | ||||
|                     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 } | ||||
|                         type: "LE_RESPONSE", | ||||
|                         domain: msg.domain, | ||||
|                         error: { message: err.message, code: err.code, stack: err.stack } | ||||
|                     }); | ||||
|                     return; | ||||
|                 } | ||||
| @ -53,7 +55,7 @@ module.exports.create = function (opts) { | ||||
| 
 | ||||
|                 //
 | ||||
|                 /* | ||||
|         var certs = require('localhost.daplie.com-certificates').merge({ | ||||
|         var certs = require('localhost.example.com-certificates').merge({ | ||||
|           subject: msg.domain | ||||
|         , altnames: [ msg.domain ] | ||||
|         , issuedAt: Date.now() | ||||
| @ -68,21 +70,23 @@ module.exports.create = function (opts) { | ||||
| 
 | ||||
|                 if (results.certs) { | ||||
|                     promise = opts.greenlock.renew(results.options, results.certs); | ||||
|         } | ||||
|         else { | ||||
|                 } else { | ||||
|                     promise = opts.greenlock.register(results.options); | ||||
|                 } | ||||
| 
 | ||||
|         promise.then(function (certs) { | ||||
|           log(opts.debug, 'Approval got certs', certs); | ||||
|                 promise.then( | ||||
|                     function(certs) { | ||||
|                         log(opts.debug, "Approval got certs", certs); | ||||
|                         // certs = { subject, domains, issuedAt, expiresAt, privkey, cert, chain };
 | ||||
|           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 }); | ||||
|                         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 }); | ||||
|                     } | ||||
|                 ); | ||||
|             }); | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
							
								
								
									
										149
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @ -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==" | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										19
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								package.json
									
									
									
									
									
								
							| @ -1,24 +1,19 @@ | ||||
| { | ||||
|     "name": "greenlock-cluster", | ||||
|   "version": "2.0.6", | ||||
|     "version": "3.0.0", | ||||
|     "description": "Use automatic letsencrypt (free ssl certs) on multiple cores or even multiple machines", | ||||
|     "main": "index.js", | ||||
|     "directories": { | ||||
|         "example": "examples" | ||||
|     }, | ||||
|     "dependencies": { | ||||
|     "le-sni-auto": "^2.0.1", | ||||
|     "greenlock": "^2.0.4", | ||||
|     "localhost.daplie.com-certificates": "^1.2.3", | ||||
|     "redirect-https": "^1.1.0" | ||||
|         "@root/greenlock-express": "^3.0.13" | ||||
|     }, | ||||
|     "devDependencies": {}, | ||||
|   "scripts": { | ||||
|     "test": "node examples/serve.js" | ||||
|   }, | ||||
|     "scripts": {}, | ||||
|     "repository": { | ||||
|         "type": "git", | ||||
|     "url": "git+https://git.daplie.com/Daplie/greenlock-cluster.git" | ||||
|         "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js.git" | ||||
|     }, | ||||
|     "keywords": [ | ||||
|         "cluster", | ||||
| @ -37,9 +32,9 @@ | ||||
|         "node.js" | ||||
|     ], | ||||
|     "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", | ||||
|   "license": "(MIT OR Apache-2.0)", | ||||
|     "license": "MPL-2.0", | ||||
|     "bugs": { | ||||
|     "url": "https://git.daplie.com/Daplie/greenlock-cluster/issues" | ||||
|         "url": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js/issues" | ||||
|     }, | ||||
|   "homepage": "https://git.daplie.com/Daplie/greenlock-cluster#readme" | ||||
|     "homepage": "https://git.coolaj86.com/coolaj86/greenlock-cluster.js" | ||||
| } | ||||
|  | ||||
							
								
								
									
										54
									
								
								worker.js
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								worker.js
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| 'use strict'; | ||||
| "use strict"; | ||||
| 
 | ||||
| function log(debug) { | ||||
|     if (!debug) { | ||||
| @ -11,36 +11,33 @@ function log(debug) { | ||||
|     console.log.apply(console, args); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| module.exports.create = function (opts) { | ||||
| 
 | ||||
| module.exports.create = function(opts) { | ||||
|     // if another worker updates the certs,
 | ||||
|     // receive a copy from master here as well
 | ||||
|     // and update the sni cache manually
 | ||||
|   process.on('message', function (msg) { | ||||
|     if ('LE_RESPONSE' === msg.type && 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) { | ||||
|     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 }); | ||||
|                 process.send({ type: "LE_REQUEST", domain: domain, options: results.options, certs: results.certs }); | ||||
| 
 | ||||
|         process.on('message', function (msg) { | ||||
|                 process.on("message", function(msg) { | ||||
|                     var err = new Error("___MESSAGE___"); | ||||
| 
 | ||||
|           log(opts.debug, 'Message from master'); | ||||
|                     log(opts.debug, "Message from master"); | ||||
|                     log(opts.debug, msg); | ||||
| 
 | ||||
|                     if (msg.domain !== domain) { | ||||
| @ -51,9 +48,9 @@ module.exports.create = function (opts) { | ||||
|                         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 } | ||||
|                             message: err.message, | ||||
|                             stack: err.stack, | ||||
|                             data: { options: workerOptions, certs: certs } | ||||
|                         }; | ||||
|                     } else { | ||||
|                         err = null; | ||||
| @ -65,24 +62,17 @@ module.exports.create = function (opts) { | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|   opts.httpsOptions = require('localhost.daplie.com-certificates').merge({ 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 | ||||
|         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); | ||||
| 
 | ||||
| 
 | ||||
|     opts.middleware = require("greenlock/lib/middleware").create(opts); | ||||
| 
 | ||||
|     return opts; | ||||
| }; | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user