| 
									
										
										
										
											2015-12-11 03:23:47 -08:00
										 |  |  | letsencrypt | 
					
						
							|  |  |  | =========== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 14:37:22 -05:00
										 |  |  | Automatic [Let's Encrypt](https://letsencrypt.org) HTTPS Certificates for node.js | 
					
						
							| 
									
										
										
										
											2015-12-11 03:23:47 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:40:03 -08:00
										 |  |  |   * Automatic HTTPS with ExpressJS | 
					
						
							|  |  |  |   * Automatic live renewal (in-process) | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  |   * On-the-fly HTTPS certificates for Dynamic DNS (in-process, no server restart) | 
					
						
							|  |  |  |   * Works with node cluster out of the box | 
					
						
							| 
									
										
										
										
											2015-12-13 06:39:37 +00:00
										 |  |  |   * usable via commandline as well | 
					
						
							| 
									
										
										
										
											2015-12-12 22:40:03 -08:00
										 |  |  |   * Free SSL (HTTPS Certificates for TLS) | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  |   * [90-day certificates](https://letsencrypt.org/2015/11/09/why-90-days.html) | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | **See Also** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * See the node-letsencrypt [Examples](https://github.com/Daplie/node-letsencrypt/tree/master/examples) | 
					
						
							|  |  |  | * [Let's Encrypt in (exactly) 90 seconds with Caddy](https://daplie.com/articles/lets-encrypt-in-literally-90-seconds/) | 
					
						
							|  |  |  | * [lego](https://github.com/xenolf/lego): Let's Encrypt for golang | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | Install | 
					
						
							|  |  |  | ======= | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | npm install --save letsencrypt | 
					
						
							| 
									
										
										
										
											2015-12-16 05:07:26 -08:00
										 |  |  | npm install --global letsencrypt-cli | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | Usage | 
					
						
							|  |  |  | ===== | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 05:07:26 -08:00
										 |  |  | ### letsencrypt-cli
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See more at [letsencrypt-cli](https://github.com/Daplie/node-letsencrypt-cli) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | letsencrypt certonly \ | 
					
						
							|  |  |  |   --agree-tos --email user@example.com \ | 
					
						
							|  |  |  |   --standalone \ | 
					
						
							|  |  |  |   --domains example.com,www.example.com \ | 
					
						
							|  |  |  |   --config-dir ~/letsencrypt/etc \ | 
					
						
							|  |  |  |   --server https://acme-staging.api.letsencrypt.org/directory \ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ls ~/letsencrypt/etc/live | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### letsencrypt-express
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TODO | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See more at [letsencrypt-express](https://github.com/Daplie/letsencrypt-express) | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 05:07:56 -08:00
										 |  |  | ### letsencrypt (the library)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 03:09:06 -08:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | var config = require('./examples/config-minimal'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 18:15:11 -08:00
										 |  |  | config.le.webrootPath = __dirname + '/tests/acme-challenge'; | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 01:19:08 -08:00
										 |  |  | var le = require('letsencrypt').create(config.le); | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | le.register({ | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  |   agreeTos: true | 
					
						
							|  |  |  | , domains: ['example.com']          // CHANGE TO YOUR DOMAIN | 
					
						
							|  |  |  | , email: 'user@email.com'           // CHANGE TO YOUR EMAIL | 
					
						
							| 
									
										
										
										
											2015-12-16 01:19:08 -08:00
										 |  |  | , standalone: true | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | }, function (err) { | 
					
						
							|  |  |  |   if (err) { | 
					
						
							|  |  |  |     console.error('[Error]: node-letsencrypt/examples/standalone'); | 
					
						
							|  |  |  |     console.error(err.stack); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     console.log('success'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   plainServer.close(); | 
					
						
							|  |  |  |   tlsServer.close(); | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // IMPORTANT | 
					
						
							| 
									
										
										
										
											2015-12-13 01:11:57 -08:00
										 |  |  | // you also need BOTH an http AND https server that serve directly | 
					
						
							|  |  |  | // from webrootPath, which might as well be a special folder reserved | 
					
						
							|  |  |  | // only for acme/letsencrypt challenges | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | // | 
					
						
							|  |  |  | // app.use('/', express.static(config.le.webrootPath)) | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **However**, due to the nature of what this library does, it has a few more "moving parts" | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:44 +00:00
										 |  |  | than what makes sense to show in a minimal snippet. | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | Examples | 
					
						
							|  |  |  | ======== | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | ### One-Time Registration
 | 
					
						
							| 
									
										
										
										
											2015-12-13 06:39:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | Register a 90-day certificate manually, on a whim | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #### Snippets
 | 
					
						
							| 
									
										
										
										
											2015-12-13 00:30:47 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | [`commandline-minimal`](https://github.com/Daplie/node-letsencrypt/blob/master/examples/commandline-minimal.js): | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | **Part 1: the Let's Encrypt client**: | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var LE = require('letsencrypt'); | 
					
						
							|  |  |  | var config = require('./config-minimal'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Note: you should make this special dir in your product and leave it empty | 
					
						
							|  |  |  | config.le.webrootPath = __dirname + '/../tests/acme-challenge'; | 
					
						
							|  |  |  | config.le.server = LE.stagingServer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Manual Registration | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | var le = LE.create(config.backend, config.le); | 
					
						
							|  |  |  | le.register({ | 
					
						
							|  |  |  |   agreeTos: true | 
					
						
							|  |  |  | , domains: ['example.com']          // CHANGE TO YOUR DOMAIN | 
					
						
							|  |  |  | , email: 'user@email.com'           // CHANGE TO YOUR EMAIL | 
					
						
							|  |  |  | }, function (err) { | 
					
						
							|  |  |  |   if (err) { | 
					
						
							|  |  |  |     console.error('[Error]: node-letsencrypt/examples/standalone'); | 
					
						
							|  |  |  |     console.error(err.stack); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     console.log('success'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   plainServer.close(); | 
					
						
							|  |  |  |   tlsServer.close(); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | **Part 2: Express Web Server**: | 
					
						
							|  |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | // | 
					
						
							|  |  |  | // Express App | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | var app = require('express')(); | 
					
						
							|  |  |  | app.use('/', le.middleware()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // HTTP & HTTPS servers | 
					
						
							|  |  |  | // (required for domain validation) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | var plainServer = require('http').createServer(app).listen(config.plainPort, function () { | 
					
						
							|  |  |  |   console.log('Listening http', this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var tlsServer = require('https').createServer({ | 
					
						
							|  |  |  |   key: config.tlsKey | 
					
						
							|  |  |  | , cert: config.tlsCert | 
					
						
							|  |  |  | , SNICallback: le.sniCallback | 
					
						
							|  |  |  | }, app).listen(config.tlsPort, function () { | 
					
						
							|  |  |  |   console.log('Listening http', this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | #### Runnable Demo
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * [commandline (standalone with "webroot")](https://github.com/Daplie/node-letsencrypt/blob/master/examples/commandline.js) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							|  |  |  | # manual standalone registration via commandline
 | 
					
						
							|  |  |  | # (runs against testing server on tls port 5001)
 | 
					
						
							|  |  |  | node examples/commandline.js example.com,www.example.com user@example.net agree | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | ### Express
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Fully Automatic HTTPS with ExpressJS using Free SSL certificates from Let's Encrypt | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | #### Snippets
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | * [Minimal ExpressJS Example](https://github.com/Daplie/node-letsencrypt/blob/master/examples/express-minimal.js) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var LE = require('letsencrypt'); | 
					
						
							|  |  |  | var config = require('./config-minimal'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Note: you should make this special dir in your product and leave it empty | 
					
						
							|  |  |  | config.le.webrootPath = __dirname + '/../tests/acme-challenge'; | 
					
						
							|  |  |  | config.le.server = LE.stagingServer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Automatically Register / Renew Domains | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | var le = LE.create(config.backend, config.le, { | 
					
						
							|  |  |  |   sniRegisterCallback: function (args, expiredCert, cb) { | 
					
						
							|  |  |  |     // Security: check that this is actually a subdomain we allow | 
					
						
							|  |  |  |     // (otherwise an attacker can cause you to rate limit against the LE server) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     var hostname = args.domains[0]; | 
					
						
							|  |  |  |     if (!/\.example\.com$/.test(hostname)) { | 
					
						
							|  |  |  |       console.error("bad domain '" + hostname + "', not a subdomain of example.com"); | 
					
						
							|  |  |  |       cb(nul, null); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // agree to the LE TOS for this domain | 
					
						
							|  |  |  |     args.agreeTos = true; | 
					
						
							|  |  |  |     args.email = 'user@example.com'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // use the cert even though it's expired | 
					
						
							|  |  |  |     if (expiredCert) { | 
					
						
							|  |  |  |       cb(null, expiredCert); | 
					
						
							|  |  |  |       cb = function () { /*ignore*/ }; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // register / renew the certificate in the background | 
					
						
							| 
									
										
										
										
											2015-12-13 00:32:25 -08:00
										 |  |  |     le.register(args, cb); | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  |   } | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Express App | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | var app = require('express')(); | 
					
						
							|  |  |  | app.use('/', le.middleware()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // HTTP & HTTPS servers | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | require('http').createServer(app).listen(config.plainPort, function () { | 
					
						
							|  |  |  |   console.log('Listening http', this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require('https').createServer({ | 
					
						
							|  |  |  |   key: config.tlsKey | 
					
						
							|  |  |  | , cert: config.tlsCert | 
					
						
							|  |  |  | , SNICallback: le.sniCallback | 
					
						
							|  |  |  | }, app).listen(config.tlsPort, function () { | 
					
						
							|  |  |  |   console.log('Listening http', this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | #### Runnable Example
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 08:05:24 +00:00
										 |  |  | * [Full ExpressJS Example](https://github.com/Daplie/node-letsencrypt/blob/master/examples/express.js) | 
					
						
							| 
									
										
										
										
											2015-12-12 22:45:21 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 06:39:37 +00:00
										 |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2015-12-12 22:45:21 -08:00
										 |  |  | # clear out the certificates
 | 
					
						
							|  |  |  | rm -rf tests/letsencrypt.* | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 06:39:37 +00:00
										 |  |  | # automatic registration and renewal (certs install as you visit the site for the first time)
 | 
					
						
							|  |  |  | # (runs against testing server on tls port 5001)
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:45:21 -08:00
										 |  |  | node examples/express.js example.com,www.example.com user@example.net agree | 
					
						
							| 
									
										
										
										
											2015-12-13 06:39:37 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:45:21 -08:00
										 |  |  | ```bash | 
					
						
							|  |  |  | # this will take a moment because it won't respond to the tls sni header until it gets the certs
 | 
					
						
							|  |  |  | curl https://example.com/ | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 06:00:30 +00:00
										 |  |  | ### non-root
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you want to run this as non-root, you can. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You just have to set node to be allowed to use root ports | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | # node
 | 
					
						
							|  |  |  | sudo setcap cap_net_bind_service=+ep /usr/local/bin/node | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | and then make sure to set all of of the following to a directory that your user is permitted to write to | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * `webrootPath` | 
					
						
							|  |  |  | * `configDir` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:16:02 +00:00
										 |  |  | API | 
					
						
							|  |  |  | === | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-16 01:11:31 -08:00
										 |  |  | LetsEncrypt.init(leConfig, handlers)                      // wraps a given | 
					
						
							|  |  |  | LetsEncrypt.create(backend, leConfig, handlers)           // wraps a given "backend" (the python or node client) | 
					
						
							|  |  |  | LetsEncrypt.stagingServer                                 // string of staging server for testing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | le.middleware()                                           // middleware for serving webrootPath to /.well-known/acme-challenge | 
					
						
							|  |  |  | le.sniCallback(hostname, function (err, tlsContext) {})   // uses fetch (below) and formats for https.SNICallback | 
					
						
							|  |  |  | le.register({ domains, email, agreeTos, ... }, cb)        // registers or renews certs for a domain | 
					
						
							|  |  |  | le.fetch({domains, email, agreeTos, ... }, cb)            // fetches certs from in-memory cache, occasionally refreshes from disk | 
					
						
							|  |  |  | le.validate(domains, cb)                                  // do some sanity checks before attempting to register | 
					
						
							|  |  |  | le.registrationFailureCallback(err, args, certInfo, cb)   // called when registration fails (not implemented yet) | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:44 -08:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-12 15:38:14 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 01:11:31 -08:00
										 |  |  | ### `LetsEncrypt.create(backend, leConfig, handlers)`
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 01:11:31 -08:00
										 |  |  | #### leConfig
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | The arguments passed here (typically `webpathRoot`, `configDir`, etc) will be merged with | 
					
						
							| 
									
										
										
										
											2015-12-12 22:19:28 +00:00
										 |  |  | any `args` (typically `domains`, `email`, and `agreeTos`) and passed to the backend whenever | 
					
						
							|  |  |  | it is called. | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Typically the backend wrapper will already merge any necessary backend-specific arguments. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Example**: | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | { webrootPath: __dirname, '/acme-challenge' | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | , fullchainTpl: '/live/:hostname/fullchain.pem' | 
					
						
							|  |  |  | , privkeyTpl: '/live/:hostname/fullchain.pem' | 
					
						
							|  |  |  | , configDir: '/etc/letsencrypt' | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:12 +00:00
										 |  |  | Note: `webrootPath` can be set as a default, semi-locally with `webrootPathTpl`, or per | 
					
						
							| 
									
										
										
										
											2015-12-16 01:11:31 -08:00
										 |  |  | registration as `webrootPath` (which overwrites `leConfig.webrootPath`). | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:12 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | #### handlers *optional*
 | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | `h.setChallenge(hostnames, name, value, cb)`: | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | default is to write to fs | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | `h.getChallenge(hostnames, value cb)` | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | default is to read from fs | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | `h.sniRegisterCallback(args, currentCerts, cb)` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The default is to immediately call `cb(null, null)` and register (or renew) in the background | 
					
						
							|  |  |  | during the `SNICallback` phase. Right now it isn't reasonable to renew during SNICallback, | 
					
						
							|  |  |  | but around February when it is possible to use ECDSA keys (as opposed to RSA at present), | 
					
						
							|  |  |  | registration will take very little time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This will not be called while another registration is already in progress. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **SECURITY WARNING**: If you use this option with a custom `h.validate()`, make sure that `args.domains` | 
					
						
							|  |  |  | refers to domains you expect, otherwise an attacker will spoof SNI and cause your server to rate-limit | 
					
						
							|  |  |  | letsencrypt.org and get blocked. Note that `le.validate()` will check A records before attempting to | 
					
						
							|  |  |  | register to help prevent such possible attacks. | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | `h.validate(domains, cb)` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When specified this will override `le.validate()`. You will need to do this if the ip address of this | 
					
						
							|  |  |  | server is not one specified in the A records for your domain. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### `le.middleware()`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | An express handler for `/.well-known/acme-challenge/<challenge>`. | 
					
						
							|  |  |  | Will call `getChallenge([hostname], key, cb)` if present or otherwise read `challenge` from disk. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Example: | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | app.use('/', le.middleware()) | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | ### `le.sniCallback(hostname, function (err, tlsContext) {});`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Will call `fetch`. If fetch does not return certificates or returns expired certificates | 
					
						
							|  |  |  | it will call `sniRegisterCallback(args, currentCerts, cb)` and then return the error, | 
					
						
							|  |  |  | the new certificates, or call `fetch` a final time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Example: | 
					
						
							|  |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-12 22:21:02 +00:00
										 |  |  | var server = require('https').createServer({ SNICallback: le.sniCallback, cert: '...', key: '...' }); | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | server.on('request', app); | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | ### `le.register({ domains, email, agreeTos, ... }, cb)`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Get certificates for a domain | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Example: | 
					
						
							| 
									
										
										
										
											2015-12-12 22:17:32 +00:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | le.register({ | 
					
						
							|  |  |  |   domains: ['example.com', 'www.example.com'] | 
					
						
							|  |  |  | , email: 'user@example.com' | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:12 +00:00
										 |  |  | , webrootPath: '/srv/www/example.com/public' | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | , agreeTos: true | 
					
						
							|  |  |  | }, function (err, certs) { | 
					
						
							|  |  |  |   // err is some error | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   console.log(certs); | 
					
						
							|  |  |  |   /* | 
					
						
							|  |  |  |   { cert: "contents of fullchain.pem" | 
					
						
							|  |  |  |   , key: "contents of privkey.pem" | 
					
						
							|  |  |  |   , renewedAt: <date in milliseconds> | 
					
						
							|  |  |  |   , duration: <duration in milliseconds (90-days)> | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  |   */ | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | ### `le.isValidDomain(hostname)`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | returns `true` if `hostname` is a valid ascii or punycode domain name. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | (also exposed on the main exported module as `LetsEncrypt.isValidDomain()`) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### `le.validate(args, cb)`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Used internally, but exposed for convenience. Checks `LetsEncrypt.isValidDomain()` | 
					
						
							| 
									
										
										
										
											2015-12-12 22:40:03 -08:00
										 |  |  | and then checks to see that the current server | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Called before `backend.register()` to validate the following: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   * the hostnames don't use any illegal characters | 
					
						
							|  |  |  |   * the server's actual public ip (via api.apiify.org) | 
					
						
							| 
									
										
										
										
											2015-12-12 22:40:03 -08:00
										 |  |  |   * the A records for said hostnames | 
					
						
							| 
									
										
										
										
											2015-12-12 22:06:36 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ### `le.fetch(args, cb)`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Used internally, but exposed for convenience. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Checks in-memory cache of certificates for `args.domains` and calls then calls `backend.fetch(args, cb)` | 
					
						
							|  |  |  | **after** merging `args` if necessary. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 05:03:48 +00:00
										 |  |  | ### `le.registrationFailureCallback(err, args, certInfo, cb)`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Not yet implemented | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This is what `args` looks like: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | { domains: ['example.com', 'www.example.com'] | 
					
						
							|  |  |  | , email: 'user@email.com' | 
					
						
							|  |  |  | , agreeTos: true | 
					
						
							|  |  |  | , configDir: '/etc/letsencrypt' | 
					
						
							|  |  |  | , fullchainTpl: '/live/:hostname/fullchain.pem'  // :hostname will be replaced with the domainname | 
					
						
							| 
									
										
										
										
											2015-12-13 01:04:12 +00:00
										 |  |  | , privkeyTpl: '/live/:hostname/privkey.pem' | 
					
						
							|  |  |  | , webrootPathTpl: '/srv/www/:hostname/public' | 
					
						
							|  |  |  | , webrootPath: '/srv/www/example.com/public'    // templated from webrootPathTpl | 
					
						
							| 
									
										
										
										
											2015-12-12 13:11:05 +00:00
										 |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This is what the implementation should look like: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | (it's expected that the client will follow the same conventions as | 
					
						
							|  |  |  | the python client, but it's not necessary) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-13 03:09:06 -08:00
										 |  |  | Change History | 
					
						
							|  |  |  | ============== | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 01:19:08 -08:00
										 |  |  | * v1.1.0 Added letiny-core, removed node-letsencrypt-python | 
					
						
							|  |  |  | * v1.0.2 Works with node-letsencrypt-python | 
					
						
							|  |  |  | * v1.0.0 Thar be dragons | 
					
						
							| 
									
										
										
										
											2015-12-13 03:09:06 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-11 03:23:47 -08:00
										 |  |  | LICENSE | 
					
						
							|  |  |  | ======= | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Dual-licensed MIT and Apache-2.0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See LICENSE |