| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | # le-store-fs
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | A greenlock keypair and certificate storage strategy with wildcard support (simpler successor to le-store-certbot). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Usage
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var greenlock = require('greenlock'); | 
					
						
							|  |  |  | var gl = greenlock.create({ | 
					
						
							|  |  |  |   configDir: '~/.config/acme' | 
					
						
							|  |  |  | , store: require('le-store-fs') | 
					
						
							|  |  |  | , approveDomains: approveDomains | 
					
						
							|  |  |  | , ... | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # File System
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The default file system layout mirrors that of le-store-certbot in order to make transitioning effortless, | 
					
						
							|  |  |  | in most situations: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | acme | 
					
						
							|  |  |  | ├── accounts | 
					
						
							|  |  |  | │   └── acme-staging-v02.api.letsencrypt.org | 
					
						
							|  |  |  | │       └── directory | 
					
						
							|  |  |  | │           └── sites@example.com.json | 
					
						
							|  |  |  | └── live | 
					
						
							|  |  |  |     ├── example.com | 
					
						
							|  |  |  |     │   ├── bundle.pem | 
					
						
							|  |  |  |     │   ├── cert.pem | 
					
						
							|  |  |  |     │   ├── chain.pem | 
					
						
							|  |  |  |     │   ├── fullchain.pem | 
					
						
							|  |  |  |     │   └── privkey.pem | 
					
						
							|  |  |  |     └── www.example.com | 
					
						
							|  |  |  |         ├── bundle.pem | 
					
						
							|  |  |  |         ├── cert.pem | 
					
						
							|  |  |  |         ├── chain.pem | 
					
						
							|  |  |  |         ├── fullchain.pem | 
					
						
							|  |  |  |         └── privkey.pem | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Wildcards & AltNames
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Working with wildcards and multiple altnames requires greenlock >= v2.7. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To do so you must set `opts.subject` and `opts.domains` within the `approvedomains()` callback. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `subject` refers to "the subject of the ssl certificate" as opposed to `domain` which indicates "the domain servername | 
					
						
							|  |  |  | used in the current request". For single-domain certificates they're always the same, but for multiple-domain | 
					
						
							|  |  |  | certificates `subject` must be the name no matter what `domain` is receiving a request. `subject` is used as | 
					
						
							|  |  |  | part of the name of the file storage path where the certificate will be saved (or retrieved). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `domains` should be the list of "altnames" on the certificate, which should include the `subject`. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Simple Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							| 
									
										
										
										
											2019-04-02 22:24:07 -06:00
										 |  |  | function approveDomains(opts) { | 
					
						
							|  |  |  |   // Allow only example.com and *.example.com (such as foo.example.com) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  |   // foo.example.com => *.example.com | 
					
						
							|  |  |  |   var wild = '*.' + opts.domain.split('.').slice(1).join('.'); | 
					
						
							| 
									
										
										
										
											2019-04-02 22:24:07 -06:00
										 |  |  |   if ('example.com' !== opts.domain && '*.example.com' !== wild) { | 
					
						
							|  |  |  |     cb(new Error(opts.domain + " is not allowed")); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-02 22:24:07 -06:00
										 |  |  |   opts.subject = 'example.com'; | 
					
						
							|  |  |  |   opts.domains = [ 'example.com', '*.example.com' ]; | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-02 22:24:07 -06:00
										 |  |  |   return Promise.resolve(opts); | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Realistic Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function approveDomains(opts, certs, cb) { | 
					
						
							|  |  |  |   var related = getRelated(opts.domain); | 
					
						
							| 
									
										
										
										
											2019-04-01 01:58:47 -06:00
										 |  |  |   if (!related) { cb(new Error(opts.domain + " is not allowed")); }; | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-01 01:58:47 -06:00
										 |  |  |   opts.subject = related.subject; | 
					
						
							|  |  |  |   opts.domains = related.domains; | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   cb({ options: opts, certs: certs }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | function getRelated(domain) { | 
					
						
							|  |  |  |   var related; | 
					
						
							|  |  |  |   var wild = '*.' + domain.split('.').slice(1).join('.'); | 
					
						
							| 
									
										
										
										
											2019-04-01 01:58:47 -06:00
										 |  |  |   if (Object.keys(allAllowedDomains).some(function (k) { | 
					
						
							|  |  |  |     return allAllowedDomains[k].some(function (name) { | 
					
						
							|  |  |  |       if (domain === name || wild === name) { | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  |         related = { subject: k, altnames: allAllowedDomains[k] }; | 
					
						
							| 
									
										
										
										
											2019-04-01 01:58:47 -06:00
										 |  |  |         return true; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2019-04-01 01:56:41 -06:00
										 |  |  |   })) { | 
					
						
							|  |  |  |     return related; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```js | 
					
						
							|  |  |  | var allAllowedDomains = { | 
					
						
							|  |  |  |   'example.com': ['example.com', '*.example.com'] | 
					
						
							|  |  |  | , 'example.net': ['example.net', '*.example.net'] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` |