| 
									
										
										
										
											2015-12-14 21:41:08 -08:00
										 |  |  | # letsencrypt-express
 | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-14 21:41:08 -08:00
										 |  |  | Free SSL and Automatic HTTPS for node.js with Express, Connect, and other middleware systems | 
					
						
							| 
									
										
										
										
											2015-12-16 05:09:40 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Coming Soon
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | We're working on it | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## In the meantime
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 05:10:08 -08:00
										 |  |  | See [examples/express-minimal.js](https://github.com/Daplie/node-letsencrypt/blob/master/examples/express-minimal.js) | 
					
						
							| 
									
										
										
										
											2015-12-16 23:06:00 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | ## Install
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | npm install --save letsencrypt-express | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ## Examples
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | **Minimal** | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  | // Note: using staging server url, remove .testing() for production | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | var lex = require('letsencrypt-express').testing(); | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | var express = require('express'); | 
					
						
							|  |  |  | var app = express(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | app.use('/', function (req, res) { | 
					
						
							|  |  |  |   res.send({ success: true }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 08:44:55 +00:00
										 |  |  | lex.create(app).listen(); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Slightly more verbose
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Note: using staging server url, remove .testing() for production | 
					
						
							|  |  |  | var lex = require('letsencrypt-express').testing(); | 
					
						
							|  |  |  | var express = require('express'); | 
					
						
							|  |  |  | var app = express(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | app.use('/', function (req, res) { | 
					
						
							|  |  |  |   res.send({ success: true }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | lex.create('./letsencrypt.config', app).listen([80], [443, 5001], function () { | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  |   console.log("ENCRYPT __ALL__ THE DOMAINS!"); | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### More Options Exposed
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | var lex = require('letsencrypt-express'); | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | var express = require('express'); | 
					
						
							|  |  |  | var app = express(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | app.use('/', function (req, res) { | 
					
						
							|  |  |  |   res.send({ success: true }); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | var results = lex.create({ | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  |   configDir: '/etc/letsencrypt' | 
					
						
							|  |  |  | , onRequest: app | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  | , server: require('letsencrypt').productionServerUrl | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | }).listen( | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // you can give just the port, or expand out to the full options | 
					
						
							|  |  |  |   [80, { port: 8080, address: 'localhost', onListening: function () { console.log('http://localhost'); } }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // you can give just the port, or expand out to the full options | 
					
						
							|  |  |  | , [443, 5001, { port: 8443, address: 'localhost' }] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // this is pretty much the default onListening handler | 
					
						
							|  |  |  | , function onListening() { | 
					
						
							|  |  |  |     var server = this; | 
					
						
							|  |  |  |     var protocol = ('requestCert' in server) ? 'https': 'http'; | 
					
						
							|  |  |  |     console.log("Listening at " + protocol + '://localhost:' + this.address().port); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // In case you need access to the raw servers (i.e. using websockets) | 
					
						
							|  |  |  | console.log(results.plainServers); | 
					
						
							|  |  |  | console.log(results.tlsServers); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### WebSockets with Let's Encrypt
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Note: you don't need to create websockets for the plain ports. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | results.tlsServers.forEach(function (server) { | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | ## API
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-17 03:15:20 +00:00
										 |  |  |                                 // checks options and sets up defaults. returns object with `listen` | 
					
						
							|  |  |  | LEX.create(options)             // (it was really just done this way to appeal to what people are used to seeing) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   lex.listen(plain, tls, fn)    // actually creates the servers and causes them to listen | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:15:20 +00:00
										 |  |  |                                 // receives an instance of letsencrypt, returns an SNICallback handler for https.createServer() | 
					
						
							|  |  |  | LEX.createSniCallback(opts)     // this will call letsencrypt.renew and letsencrypt.register as appropriate | 
					
						
							|  |  |  |                                 // it will randomly stagger renewals such that they don't all happen at once on boot | 
					
						
							|  |  |  |                                 // or at any other time. registrations will be handled as per `handleRegistration` | 
					
						
							|  |  |  |   opts = { | 
					
						
							|  |  |  |     letsencrypt: <obj>          // letsencrypt instance | 
					
						
							|  |  |  |   , memorizeFor: <1 day>        // how long to wait before checking the disk for updated certificates | 
					
						
							|  |  |  |   , renewWithin: <3 days>       // the first possible moment the certificate staggering should begin | 
					
						
							|  |  |  |   , failedWait:  <5 minutes>    // how long to wait before trying again if the certificate registration failed | 
					
						
							| 
									
										
										
										
											2015-12-17 05:08:14 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                                 // registrations are NOT approved automatically by default due to security concerns | 
					
						
							|  |  |  |   , approveRegistration: func   // (someone can spoof servername indication to your server and cause you to be rate-limited) | 
					
						
							|  |  |  |                                 // but you can implement handling of them if you wish | 
					
						
							|  |  |  |                                 // (note that you should probably call the callback immediately with a tlsContext) | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    function (hostname, cb) { cb(null, null); } | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // example    function (hostname, cb) { | 
					
						
							|  |  |  |                                 //              cb(null, { domains: [hostname], agreeTos: true, email: 'user@example.com' }); | 
					
						
							|  |  |  |                                 //            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   , handleRenewFailure: func    // renewals are automatic, but sometimes they may fail. If that happens, you should handle it | 
					
						
							|  |  |  |                                 // (note that renewals happen in the background) | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    function (err, letsencrypt, hostname, certInfo) {} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:15:20 +00:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:15:20 +00:00
										 |  |  |                                 // uses `opts.webrootPath` to read from the filesystem | 
					
						
							|  |  |  | LEX.getChallenge(opts, hostname, key cb)   | 
					
						
							| 
									
										
										
										
											2015-12-17 03:03:07 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 23:06:00 +00:00
										 |  |  | ## Options
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If any of these values are `undefined` or `null` the will assume use reasonable defaults. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Partially defined values will be merged with the defaults. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Setting the value to `false` will, in many cases (as documented), disable the defaults. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  | configDir: string               // string     the letsencrypt configuration path (de facto /etc/letsencrypt) | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    os.homedir() + '/letsencrypt/etc' | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 23:06:00 +00:00
										 |  |  | webrootPath: string             // string     a path to a folder where temporary challenge files will be stored and read | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    os.tmpdir() + '/acme-challenge' | 
					
						
							| 
									
										
										
										
											2015-12-16 23:06:00 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | getChallenge: func | false      // false      do not handle getChallenge | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // func       Example: | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    function (defaults, hostname, key, cb) { | 
					
						
							|  |  |  |                                 //              var filename = path.join(defaults.webrootPath.replace(':hostname', hostname), key); | 
					
						
							|  |  |  |                                 //              fs.readFile(filename, 'ascii', function (cb, text) { | 
					
						
							|  |  |  |                                 //                cb(null, text); | 
					
						
							|  |  |  |                                 //              }) | 
					
						
							|  |  |  |                                 //            } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | httpsOptions: object            // object     will be merged with internal defaults and passed to https.createServer() | 
					
						
							|  |  |  |                                 //            { pfx, key, cert, passphrase, ca, ciphers, rejectUnauthorized, secureProtocol } | 
					
						
							|  |  |  |                                 //            See https://nodejs.org/api/https.html | 
					
						
							|  |  |  |                                 //            Note: if SNICallback is specified, it will be run *before* | 
					
						
							|  |  |  |                                 //            the internal SNICallback that manages automated certificates | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    uses a localhost cert and key to prevent https.createServer() from throwing an error | 
					
						
							|  |  |  |                                 //            and also uses our SNICallback, which manages certificates | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | sniCallback: func               // func       replace the default sniCallback handler (which manages certificates) with your own | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | letsencrypt: object             // object     configure the letsencrypt object yourself and pass it in directly | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    we create the letsencrypt object using parameters you specify | 
					
						
							| 
									
										
										
										
											2015-12-17 01:20:56 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | server: url                     // url        use letsencrypt.productionServerUrl (i.e. https://acme-v01.api.letsencrypt.org/directory) | 
					
						
							|  |  |  |                                 //            or letsencrypt.stagingServerUrl     (i.e. https://acme-staging.api.letsencrypt.org/directory) | 
					
						
							|  |  |  |                                 // | 
					
						
							|  |  |  |                                 // default    production | 
					
						
							| 
									
										
										
										
											2015-12-16 23:06:00 +00:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2015-12-17 00:51:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Heroku?
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This doesn't work on heroku because heroku uses a proxy with built-in https | 
					
						
							|  |  |  | (which is a smart thing to do) and besides, they want you to pay big bucks | 
					
						
							|  |  |  | for https. (hopefully not for long?...) |