update guide
This commit is contained in:
		
							parent
							
								
									b9bcdb5776
								
							
						
					
					
						commit
						fc04a0445c
					
				| @ -6,7 +6,29 @@ All options described for `Greenlock.create({...})` also apply to the Greenlock | ||||
| 
 | ||||
| # Overview of Major Differences | ||||
| 
 | ||||
| ## Greenlock JavaScript API greatly reduced | ||||
| -   Reduced API | ||||
| -   No code in the config | ||||
|     -   (config is completely serializable) | ||||
| -   Manager callbacks replace `approveDomains` | ||||
| -   Greenlock Express does more, with less config | ||||
|     -   cluster is supported out-of-the-box | ||||
|     -   high-performance | ||||
|     -   scalable | ||||
| -   ACME challenges are simplified | ||||
|     -   init | ||||
|     -   zones (dns-01) | ||||
|     -   set | ||||
|     -   get | ||||
|     -   remove | ||||
| -   Store callbacks are simplified | ||||
|     -   accounts | ||||
|         -   checkKeypairs | ||||
|     -   certificates | ||||
|         -   checkKeypairs | ||||
|         -   check | ||||
|         -   set | ||||
| 
 | ||||
| # Greenlock JavaScript API greatly reduced | ||||
| 
 | ||||
| Whereas before there were many different methods with nuance differences, | ||||
| now there's just `create`, `get`, `renew`, and sometimes `add` (). | ||||
| @ -18,6 +40,9 @@ now there's just `create`, `get`, `renew`, and sometimes `add` (). | ||||
|     -   (retrieves, issues, renews, all-in-one) | ||||
| -   _optional_ Greenlock.add({ subject, altnames, subscriberEmail }) | ||||
|     -   (partially replaces `approveDomains`) | ||||
| 
 | ||||
| Also, some disambiguation on terms: | ||||
| 
 | ||||
| -   `domains` was often ambiguous and confusing, it has been replaced by: | ||||
|     -   `subject` refers to the subject of a certificate - the primary domain | ||||
|     -   `altnames` refers to the domains in the SAN (Subject Alternative Names) section of the certificate | ||||
| @ -40,7 +65,7 @@ var greenlock = Greenlock.create({ | ||||
| 
 | ||||
|     // used as the contact for critical bug and security notices | ||||
|     // should be the same as pkg.author.email | ||||
|         maintainerEmail: 'jon@example.com' | ||||
|     maintainerEmail: 'jon@example.com', | ||||
| 
 | ||||
|     // used for logging background events and errors | ||||
|     notify: function(ev, args) { | ||||
| @ -130,27 +155,38 @@ with a few extra that are specific to Greenlock Express: | ||||
| ```js | ||||
| require('@root/greenlock-express') | ||||
|     .init(function() { | ||||
| 		return { | ||||
|         // This object will be passed to Greenlock.create() | ||||
| 
 | ||||
|         var options = { | ||||
|             // some options, like cluster, are special to Greenlock Express | ||||
| 
 | ||||
|             cluster: false, | ||||
| 
 | ||||
|             // The rest are the same as for Greenlock | ||||
| 
 | ||||
|             packageAgent: pkg.name + '/' + pkg.version, | ||||
|             maintainerEmail: 'jon@example.com', | ||||
|             notify: function(ev, args) { | ||||
| 				if ('error' === ev || 'warning' === ev) { | ||||
| 					console.error(ev, args); | ||||
| 					return; | ||||
| 				} | ||||
|                 console.info(ev, args); | ||||
|             } | ||||
|         }; | ||||
| 
 | ||||
|         return options; | ||||
|     }) | ||||
|     .serve(function(glx) { | ||||
|         // will start servers on port 80 and 443 | ||||
| 
 | ||||
|         glx.serveApp(function(req, res) { | ||||
|             res.end('Hello, Encrypted World!'); | ||||
|         }); | ||||
| 
 | ||||
|         // you can get access to the raw server (i.e. for websockets) | ||||
| 
 | ||||
|         glx.httpsServer(); // returns raw server object | ||||
|     }); | ||||
| ``` | ||||
| 
 | ||||
| ## _Manager_ replaces `approveDomains` | ||||
| # _Manager_ replaces `approveDomains` | ||||
| 
 | ||||
| `approveDomains` was always a little confusing. Most people didn't need it. | ||||
| 
 | ||||
| @ -178,24 +214,7 @@ The config file should look something like this: | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| You can specify a `acme-dns-01-*` or `acme-http-01-*` challenge plugin globally, or per-site. The same is true with `greenlock-store-*` plugins: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| 	"subscriberEmail": "jon@example.com", | ||||
| 	"agreeToTerms": true, | ||||
| 	"sites": { | ||||
| 		"example.com": { | ||||
| 			"subject": "example.com", | ||||
| 			"altnames": ["example.com", "www.example.com"] | ||||
| 		} | ||||
| 	}, | ||||
| 	"store": { | ||||
| 		"module": "greenlock-store-fs", | ||||
| 		"basePath": "~/.config/greenlock" | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
| You can specify a `acme-dns-01-*` or `acme-http-01-*` challenge plugin globally, or per-site. | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
| @ -216,7 +235,26 @@ You can specify a `acme-dns-01-*` or `acme-http-01-*` challenge plugin globally, | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Customer Manager | ||||
| The same is true with `greenlock-store-*` plugins: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|     "subscriberEmail": "jon@example.com", | ||||
|     "agreeToTerms": true, | ||||
|     "sites": { | ||||
|         "example.com": { | ||||
|             "subject": "example.com", | ||||
|             "altnames": ["example.com", "www.example.com"] | ||||
|         } | ||||
|     }, | ||||
|     "store": { | ||||
|         "module": "greenlock-store-fs", | ||||
|         "basePath": "~/.config/greenlock" | ||||
|     } | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Customer Manager, the lazy way | ||||
| 
 | ||||
| At the very least you have to implement `find({ servername })`. | ||||
| 
 | ||||
| @ -254,7 +292,9 @@ If you want to use wildcards or local domains, you must specify the `dns-01` cha | ||||
| 
 | ||||
| ```js | ||||
| function find(options) { | ||||
| 	var servername = options.servername; // www.example.com | ||||
|     var subject = options.subject; | ||||
|     // may include wildcard | ||||
|     var altnames = options.altnames; | ||||
|     var wildname = options.wildname; // *.example.com | ||||
|     return Promise.resolve([ | ||||
|         { | ||||
| @ -268,6 +308,85 @@ function find(options) { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Customer Manager, complete | ||||
| 
 | ||||
| To use a fully custom manager, you give the npm package name, or absolute path to the file to load | ||||
| 
 | ||||
| ```js | ||||
| Greenlock.create({ | ||||
|     // Greenlock Options | ||||
|     maintainerEmail: 'jon@example.com', | ||||
|     packageAgent: 'my-package/v2.1.1', | ||||
|     notify: notify, | ||||
| 
 | ||||
|     // file path or npm package name | ||||
|     manager: '/path/to/manager.js', | ||||
|     // options that get passed to the manager | ||||
|     myFooOption: 'whatever' | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The manager itself is, again relatively simple: | ||||
| 
 | ||||
| -   find(options) | ||||
| -   add(siteConfig) | ||||
| -   update(updates) | ||||
| -   remove(options) | ||||
| -   defaults(globalOptions) (as setter) | ||||
| -   defaults() => globalOptions (as getter) | ||||
| 
 | ||||
| `/path/to/manager.js`: | ||||
| 
 | ||||
| ```js | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.create = function() { | ||||
|     var manager = {}; | ||||
| 
 | ||||
|     manager.find = async function({ subject, altnames, renewBefore }) { | ||||
|         if (subject) { | ||||
|             return getSiteConfigBySubject(subject); | ||||
|         } | ||||
| 
 | ||||
|         if (altnames) { | ||||
|             // may include wildcards | ||||
|             return getSiteConfigByAnyAltname(altnames); | ||||
|         } | ||||
| 
 | ||||
|         if (renewBefore) { | ||||
|             return getSiteConfigsWhereRenewAtIsLessThan(renewBefore); | ||||
|         } | ||||
| 
 | ||||
|         return []; | ||||
|     }; | ||||
| 
 | ||||
|     manage.add = function({ subject, altnames }) { | ||||
|         return setSiteConfig(subject, { subject, altnames }); | ||||
|     }; | ||||
| 
 | ||||
|     manage.update = function({ subject, renewAt }) { | ||||
|         // update the `renewAt` date of the site by `subject` | ||||
|         return mergSiteConfig(subject, { renewAt }); | ||||
|     }; | ||||
| 
 | ||||
|     manage.remove = function({ subject, altname }) { | ||||
|         if (subject) { | ||||
|             return removeSiteConfig(subject); | ||||
|         } | ||||
| 
 | ||||
|         return removeFromSiteConfigAndResetRenewAtToZero(altname); | ||||
|     }; | ||||
| 
 | ||||
|     // set the global config | ||||
|     manage.defaults = function(options) { | ||||
|         if (!options) { | ||||
|             return getGlobalConfig(); | ||||
|         } | ||||
|         return mergeGlobalConfig(options); | ||||
|     }; | ||||
| }; | ||||
| ``` | ||||
| 
 | ||||
| # ACME Challenge Plugins | ||||
| 
 | ||||
| The ACME challenge plugins are just a few simple callbacks: | ||||
| @ -309,40 +428,46 @@ If you are just implenting in-house and are not going to publish a module, you c | ||||
| `/path/to/project/my-hacky-store.js`: | ||||
| 
 | ||||
| ```js | ||||
| 'use strict'; | ||||
| 
 | ||||
| module.exports.create = function(options) { | ||||
|     // ex: /path/to/account.ecdsa.jwk.json | ||||
|     var accountJwk = require(options.accountJwkPath); | ||||
|     // ex: /path/to/privkey.rsa.pem | ||||
|     var serverPem = fs.readFileSync(options.serverPemPath, 'ascii'); | ||||
| 	var store = {}; | ||||
|     var accounts = {}; | ||||
|     var certificates = {}; | ||||
|     var store = { accounts, certificates }; | ||||
| 
 | ||||
|     // bare essential account callbacks | ||||
| 	store.accounts = { | ||||
| 		checkKeypair: function() { | ||||
|     accounts.checkKeypair = function() { | ||||
|         // ignore all options and just return a single, global keypair | ||||
| 
 | ||||
|         return Promise.resolve({ | ||||
|             privateKeyJwk: accountJwk | ||||
|         }); | ||||
| 		}, | ||||
| 		setKeypair: function() { | ||||
|     }; | ||||
|     accounts.setKeypair = function() { | ||||
|         // this will never get called if checkKeypair always returns | ||||
| 
 | ||||
|         return Promise.resolve({}); | ||||
| 		} | ||||
|     }; | ||||
| 
 | ||||
|     // bare essential cert and key callbacks | ||||
| 	store.certificates = { | ||||
| 		checkKeypair: function() { | ||||
|     certificates.checkKeypair = function() { | ||||
|         // ignore all options and just return a global server keypair | ||||
| 
 | ||||
|         return { | ||||
|             privateKeyPem: serverPem | ||||
|         }; | ||||
| 		}, | ||||
| 		setKeypair: function() { | ||||
|     }; | ||||
|     certificates.setKeypair = function() { | ||||
|         // never gets called if checkKeypair always returns an existing key | ||||
| 
 | ||||
|         return Promise.resolve(null); | ||||
| 		}, | ||||
| 		check: function(args) { | ||||
|     }; | ||||
| 
 | ||||
|     certificates.check = function(args) { | ||||
|         var subject = args.subject; | ||||
|         // make a database call or whatever to get a certificate | ||||
|         return goGetCertBySubject(subject).then(function() { | ||||
| @ -353,8 +478,8 @@ module.exports.create = function(options) { | ||||
|                 } | ||||
|             }; | ||||
|         }); | ||||
| 		}, | ||||
| 		set: function(args) { | ||||
|     }; | ||||
|     certificates.set = function(args) { | ||||
|         var subject = args.subject; | ||||
|         var cert = args.pems.cert; | ||||
|         var chain = args.pems.chain; | ||||
| @ -365,7 +490,6 @@ module.exports.create = function(options) { | ||||
|             cert, | ||||
|             chain | ||||
|         }); | ||||
| 		} | ||||
|     }; | ||||
| }; | ||||
| ``` | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user