more
This commit is contained in:
parent
260f0592be
commit
419b84a1ab
87
README.md
87
README.md
|
@ -1,4 +1,5 @@
|
||||||
# letsencrypt-express
|
# letsencrypt-express
|
||||||
|
|
||||||
Free SSL and Automatic HTTPS for node.js with Express, Connect, and other middleware systems
|
Free SSL and Automatic HTTPS for node.js with Express, Connect, and other middleware systems
|
||||||
|
|
||||||
## Coming Soon
|
## Coming Soon
|
||||||
|
@ -9,6 +10,78 @@ We're working on it
|
||||||
|
|
||||||
See [examples/express-minimal.js](https://github.com/Daplie/node-letsencrypt/blob/master/examples/express-minimal.js)
|
See [examples/express-minimal.js](https://github.com/Daplie/node-letsencrypt/blob/master/examples/express-minimal.js)
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install --save letsencrypt-express
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
**Minimal**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var le = require('letsencrypt-express');
|
||||||
|
var express = require('express');
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
app.use('/', function (req, res) {
|
||||||
|
res.send({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
le.create('/etc/letsencrypt', app).listen([80], [443, 5001], function () {
|
||||||
|
console.log("ENCRYPT **ALL** THE DOMAINS!");
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### More Options Exposed
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var le = require('letsencrypt-express');
|
||||||
|
var express = require('express');
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
app.use('/', function (req, res) {
|
||||||
|
res.send({ success: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
var results = le.create({
|
||||||
|
configDir: '/etc/letsencrypt'
|
||||||
|
, onRequest: app
|
||||||
|
}).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) {
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
If any of these values are `undefined` or `null` the will assume use reasonable defaults.
|
If any of these values are `undefined` or `null` the will assume use reasonable defaults.
|
||||||
|
@ -18,6 +91,9 @@ Partially defined values will be merged with the defaults.
|
||||||
Setting the value to `false` will, in many cases (as documented), disable the defaults.
|
Setting the value to `false` will, in many cases (as documented), disable the defaults.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
configDir: string //
|
||||||
|
|
||||||
|
|
||||||
webrootPath: string // string a path to a folder where temporary challenge files will be stored and read
|
webrootPath: string // string a path to a folder where temporary challenge files will be stored and read
|
||||||
// default os.tmpdir() + path.sep + 'acme-challenge'
|
// default os.tmpdir() + path.sep + 'acme-challenge'
|
||||||
|
|
||||||
|
@ -45,4 +121,15 @@ httpsOptions: object // object will be merged with internal defau
|
||||||
|
|
||||||
|
|
||||||
sniCallback: func // func replace the default sniCallback handler (which manages certificates) with your own
|
sniCallback: func // func replace the default sniCallback handler (which manages certificates) with your own
|
||||||
|
|
||||||
|
|
||||||
|
letsencrypt: object // object configure the letsencrypt object yourself and pass it in directly
|
||||||
|
//
|
||||||
|
// default we create the letsencrypt object using parameters you specify
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 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?...)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
|
// TODO handle templating :hostname in letsencrypt proper
|
||||||
|
|
||||||
|
// Note: we're explicitly doing this on the filesystem
|
||||||
|
// rather than in-memory to support node cluster
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
set: function setChallenge(args, hostname, key, value, cb) {
|
||||||
|
var keyfile = path.join((args.webrootPath || args.webrootTpl).replace(':hostname', hostname), key);
|
||||||
|
|
||||||
|
fs.writeFile(keyfile, value, 'utf8', cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
, get: function getChallenge(args, hostname, key, cb) {
|
||||||
|
var keyfile = path.join((args.webrootPath || args.webrootTpl).replace(':hostname', hostname), key);
|
||||||
|
|
||||||
|
fs.readFile(keyfile, 'utf8', cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
, remove: function removeChallenge(args, hostname, key, cb) {
|
||||||
|
var keyfile = path.join((args.webrootPath || args.webrootTpl).replace(':hostname', hostname), key);
|
||||||
|
|
||||||
|
// Note: it's not actually terribly important that we wait for the unlink callback
|
||||||
|
// but it's a polite thing to do - and we're polite people!
|
||||||
|
fs.unlink(keyfile, cb);
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,22 +1,10 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
var challengeStore = require('./lib/challange-handlers');
|
||||||
|
|
||||||
function getChallenge(args, hostname, key, cb) {
|
function create(obj, app) {
|
||||||
var fs = require('fs');
|
var LE = require('letsencrypt');
|
||||||
var keyfile = path.join((args.webrootPath || args.webrootTpl).replace(':hostname', hostname), key);
|
|
||||||
|
|
||||||
fs.readFile(keyfile, 'utf8', function (err, text) {
|
|
||||||
if (err) {
|
|
||||||
cb(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(null, text);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function create(obj) {
|
|
||||||
var https = require('https');
|
var https = require('https');
|
||||||
var http = require('http');
|
var http = require('http');
|
||||||
|
|
||||||
|
@ -26,12 +14,23 @@ function create(obj) {
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
obj = {};
|
obj = {};
|
||||||
}
|
}
|
||||||
else if ('function' === typeof obj) {
|
|
||||||
|
if ('string' === typeof obj) {
|
||||||
|
obj = {
|
||||||
|
configDir: obj
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('function' === typeof obj) {
|
||||||
obj = {
|
obj = {
|
||||||
onRequest: obj
|
onRequest: obj
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ('function' === typeof app) {
|
||||||
|
obj.onRequest = obj.onRequest || app;
|
||||||
|
}
|
||||||
|
|
||||||
if (!obj.getChallenge) {
|
if (!obj.getChallenge) {
|
||||||
if (false !== obj.getChallenge) {
|
if (false !== obj.getChallenge) {
|
||||||
obj.getChallenge = getChallenge;
|
obj.getChallenge = getChallenge;
|
||||||
|
@ -41,11 +40,18 @@ function create(obj) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!obj.onRequest) {
|
if (!obj.onRequest && false !== obj.onRequest) {
|
||||||
console.warn("You did not specify args.onRequest, using 'Hello, World!'");
|
console.warn("You should either do args.onRequest = app or server.on('request', app),"
|
||||||
obj.onRequest = function (req, res) {
|
+ " otherwise only acme-challenge requests will be handled (and the rest will hang)");
|
||||||
res.end('Hello, World!');
|
console.warn("You can silence this warning by setting args.onRequest = false");
|
||||||
};
|
}
|
||||||
|
|
||||||
|
if (!obj.letsencrypt) {
|
||||||
|
//LE.merge(obj, );
|
||||||
|
obj.letsencrypt = LE.create(obj, {
|
||||||
|
setChallenge: setChallenge
|
||||||
|
, removeChallenge: removeChallenge
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function acmeResponder(req, res) {
|
function acmeResponder(req, res) {
|
||||||
|
@ -142,7 +148,7 @@ function create(obj) {
|
||||||
|
|
||||||
// deleting creates a "slow object", but that's okay (we only use it once)
|
// deleting creates a "slow object", but that's okay (we only use it once)
|
||||||
return results;
|
return results;
|
||||||
};
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
listen: listen
|
listen: listen
|
||||||
|
@ -151,4 +157,6 @@ function create(obj) {
|
||||||
|
|
||||||
module.exports = create;
|
module.exports = create;
|
||||||
module.exports.create = create;
|
module.exports.create = create;
|
||||||
module.exports.getChallenge = getChallenge;
|
module.exports.setChallenge = challengeStore.set;
|
||||||
|
module.exports.getChallenge = challengeStore.get;
|
||||||
|
module.exports.removeChallenge = challengeStore.remove;
|
||||||
|
|
Loading…
Reference in New Issue