use letsencrypt v2
This commit is contained in:
parent
688cb49c0a
commit
971a47eb76
13
README.md
13
README.md
|
@ -1,7 +1,7 @@
|
||||||
[![Join the chat at https://gitter.im/Daplie/letsencrypt-express](https://badges.gitter.im/Daplie/letsencrypt-express.svg)](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
[![Join the chat at https://gitter.im/Daplie/letsencrypt-express](https://badges.gitter.im/Daplie/letsencrypt-express.svg)](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
|
|
||||||
| [letsencrypt (library)](https://github.com/Daplie/node-letsencrypt)
|
| [letsencrypt (library)](https://github.com/Daplie/node-letsencrypt)
|
||||||
| **letsencrypt-cli**
|
| **letsencrypt-cli**
|
||||||
| [letsencrypt-express](https://github.com/Daplie/letsencrypt-express)
|
| [letsencrypt-express](https://github.com/Daplie/letsencrypt-express)
|
||||||
| [letsencrypt-koa](https://github.com/Daplie/letsencrypt-koa)
|
| [letsencrypt-koa](https://github.com/Daplie/letsencrypt-koa)
|
||||||
| [letsencrypt-hapi](https://github.com/Daplie/letsencrypt-hapi)
|
| [letsencrypt-hapi](https://github.com/Daplie/letsencrypt-hapi)
|
||||||
|
@ -138,7 +138,7 @@ you could change the permissions on them. **Probably a BAD IDEA**. Probabry a se
|
||||||
|
|
||||||
```
|
```
|
||||||
# PROBABLY A BAD IDEA
|
# PROBABLY A BAD IDEA
|
||||||
sudo chown -R $(whoami) /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt
|
sudo chown -R $(whoami) /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Command line Options
|
## Command line Options
|
||||||
|
@ -159,10 +159,13 @@ Options:
|
||||||
|
|
||||||
--debug BOOLEAN show traces and logs
|
--debug BOOLEAN show traces and logs
|
||||||
|
|
||||||
--tls-sni-01-port NUMBER Port number to perform tls-sni-01 challenge.
|
--tls-sni-01-port NUMBER Use TLS-SNI-01 challenge type with this port. (Default is 443)
|
||||||
Boulder in testing mode defaults to 5001. (default: 443 and 5001)
|
(must be 443 with most production servers) (Boulder allows 5001 in testing mode)
|
||||||
|
|
||||||
--http-01-port [NUMBER] Port used in the SimpleHttp challenge. (Default is 80)
|
--http-01-port [NUMBER] Use HTTP-01 challenge type with this port, used for SimpleHttp challenge. (Default is 80)
|
||||||
|
(must be 80 with most production servers)
|
||||||
|
|
||||||
|
--dns-01 Use DNS-01 challenge type.
|
||||||
|
|
||||||
--rsa-key-size [NUMBER] Size (in bits) of the RSA key. (Default is 2048)
|
--rsa-key-size [NUMBER] Size (in bits) of the RSA key. (Default is 2048)
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,15 @@ cli.parse({
|
||||||
, duplicate: [ false, " Allow getting a certificate that duplicates an existing one", 'boolean', false ]
|
, duplicate: [ false, " Allow getting a certificate that duplicates an existing one", 'boolean', false ]
|
||||||
, 'agree-tos': [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
|
, 'agree-tos': [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ]
|
||||||
, debug: [ false, " show traces and logs", 'boolean', false ]
|
, debug: [ false, " show traces and logs", 'boolean', false ]
|
||||||
, 'tls-sni-01-port': [ false, " Port number to perform tls-sni-01 challenge. Boulder in testing mode defaults to 5001. (default: 443,5001)", 'string' ]
|
, 'tls-sni-01-port': [ false, " Use TLS-SNI-01 challenge type with this port (only port 443 is valid with most production servers) (default: 443,5001)", 'string' ]
|
||||||
, 'http-01-port': [ false, " Port used in the SimpleHttp challenge. (default: 80)", 'string' ]
|
, 'http-01-port': [ false, " Use HTTP-01 challenge type with this port (only port 80 is valid with most production servers) (default: 80)", 'string' ]
|
||||||
|
, 'dns-01': [ false, " Use DNS-01 challange type", 'boolean', false ]
|
||||||
, 'rsa-key-size': [ false, " Size (in bits) of the RSA key.", 'int', 2048 ]
|
, 'rsa-key-size': [ false, " Size (in bits) of the RSA key.", 'int', 2048 ]
|
||||||
, 'cert-path': [ false, " Path to where new cert.pem is saved", 'string',':config/live/:hostname/cert.pem' ]
|
, 'cert-path': [ false, " Path to where new cert.pem is saved", 'string',':configDir/live/:hostname/cert.pem' ]
|
||||||
, 'fullchain-path': [ false, " Path to where new fullchain.pem (cert + chain) is saved", 'string', ':config/live/:hostname/fullchain.pem' ]
|
, 'fullchain-path': [ false, " Path to where new fullchain.pem (cert + chain) is saved", 'string', ':configDir/live/:hostname/fullchain.pem' ]
|
||||||
, 'chain-path': [ false, " Path to where new chain.pem is saved", 'string', ':config/live/:hostname/chain.pem' ]
|
, 'chain-path': [ false, " Path to where new chain.pem is saved", 'string', ':configDir/live/:hostname/chain.pem' ]
|
||||||
, 'domain-key-path': [ false, " Path to privkey.pem to use for domain (default: generate new)", 'string' ]
|
, 'domain-key-path': [ false, " Path to privkey.pem to use for domain (default: generate new)", 'string' ]
|
||||||
|
, 'account-key-path': [ false, " Path to privkey.pem to use for account (default: generate new)", 'string' ]
|
||||||
, 'config-dir': [ false, " Configuration directory.", 'string', '~/letsencrypt/etc/' ]
|
, 'config-dir': [ false, " Configuration directory.", 'string', '~/letsencrypt/etc/' ]
|
||||||
, server: [ false, " ACME Directory Resource URI.", 'string', 'https://acme-v01.api.letsencrypt.org/directory)' ]
|
, server: [ false, " ACME Directory Resource URI.", 'string', 'https://acme-v01.api.letsencrypt.org/directory)' ]
|
||||||
, standalone: [ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ]
|
, standalone: [ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ]
|
||||||
|
@ -49,7 +51,7 @@ cli.main(function(_, options) {
|
||||||
var val = args[key];
|
var val = args[key];
|
||||||
|
|
||||||
if ('string' === typeof val) {
|
if ('string' === typeof val) {
|
||||||
val = val.replace(/\:config/, args.configDir);
|
val = val.replace(/(\:configDir)|(\:config)/, args.configDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
args[key] = val;
|
args[key] = val;
|
||||||
|
@ -88,54 +90,6 @@ cli.main(function(_, options) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var LE = require('letsencrypt');
|
require('../').run(args);
|
||||||
var handlers;
|
|
||||||
|
|
||||||
if (args.webrootPath) {
|
|
||||||
handlers = require('../lib/webroot').create(args);
|
|
||||||
}
|
|
||||||
else /*if (args.standalone)*/ {
|
|
||||||
handlers = require('../lib/standalone').create();
|
|
||||||
handlers.startServers(args.http01Port || [80], args.tlsSni01Port || [443, 5001]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// let LE know that we're handling standalone / webroot here
|
|
||||||
LE.create({
|
|
||||||
manual: true
|
|
||||||
, debug: args.debug
|
|
||||||
, configDir: args.configDir
|
|
||||||
, privkeyPath: ':config/live/:hostname/privkey.pem' //args.privkeyPath
|
|
||||||
, fullchainPath: args.fullchainPath
|
|
||||||
, certPath: args.certPath
|
|
||||||
, chainPath: args.chainPath
|
|
||||||
}, handlers).register(args, function (err, results) {
|
|
||||||
if (err) {
|
|
||||||
console.error('[Error]: letsencrypt-cli');
|
|
||||||
console.error(err.stack || err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!results || ('object' !== typeof results)) {
|
|
||||||
console.error("Error: An unknown error occurred. My best guess is that we got an error that we're not used to from the ACME server and accidentally interpretted it as a success... or forgot to expose the error.");
|
|
||||||
console.error(results);
|
|
||||||
err = new Error("Here's a stack trace, in case it helps:");
|
|
||||||
console.error(err.stack);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (handlers.closeServers) {
|
|
||||||
handlers.closeServers();
|
|
||||||
}
|
|
||||||
|
|
||||||
// should get back account, path to certs, pems, etc?
|
|
||||||
console.log('\nCertificates installed at:');
|
|
||||||
console.log(Object.keys(results).filter(function (key) {
|
|
||||||
return /Path/.test(key);
|
|
||||||
}).map(function (key) {
|
|
||||||
return results[key];
|
|
||||||
}).join('\n'));
|
|
||||||
|
|
||||||
process.exit(0);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
letsencrypt certonly \
|
node bin/letsencrypt certonly \
|
||||||
--agree-tos --email coolaj86+le.1010@gmail.com \
|
--agree-tos --email 'coolaj86+le.1010@gmail.com' \
|
||||||
--standalone \
|
--standalone \
|
||||||
--domains pokemap.hellabit.com,www.pokemap.hellabit.com \
|
--domains pokemap.hellabit.com,www.pokemap.hellabit.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory \
|
--server https://acme-staging.api.letsencrypt.org/directory \
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var LE = require('letsencrypt');
|
||||||
|
|
||||||
|
module.exports.run = function (args) {
|
||||||
|
var leChallenge;
|
||||||
|
var leStore;
|
||||||
|
var servers;
|
||||||
|
var USE_DNS = {};
|
||||||
|
|
||||||
|
var challengeType;
|
||||||
|
if (args.dns01) {
|
||||||
|
challengeType = 'dns-01';
|
||||||
|
args.webrootPath = '';
|
||||||
|
args.standalone = USE_DNS;
|
||||||
|
} else if (args.tlsSni01Port) {
|
||||||
|
challengeType = 'tls-sni-01';
|
||||||
|
} else /*if (args.http01Port)*/ {
|
||||||
|
challengeType = 'http-01';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.webrootPath) {
|
||||||
|
// webrootPath is all that really matters here
|
||||||
|
leChallenge = require('./lib/webroot').create({ webrootPath: args.webrootPath });
|
||||||
|
}
|
||||||
|
else if (USE_DNS !== args.standalone) {
|
||||||
|
leChallenge = require('./lib/standalone').create({});
|
||||||
|
servers = require('./lib/servers').create(leChallenge).startServers(
|
||||||
|
args.http01Port || [80], args.tlsSni01Port || [443, 5001]
|
||||||
|
, { debug: args.debug }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
leStore = require('le-store-certbot').create({
|
||||||
|
configDir: args.configDir
|
||||||
|
, privkeyPath: args.domainKeyPath || ':configDir/live/:hostname/privkey.pem' //args.privkeyPath
|
||||||
|
, fullchainPath: args.fullchainPath
|
||||||
|
, certPath: args.certPath
|
||||||
|
, chainPath: args.chainPath
|
||||||
|
, webrootPath: args.webrootPath
|
||||||
|
, domainKeyPath: args.domainKeyPath
|
||||||
|
, accountKeyPath: args.accountKeyPath
|
||||||
|
});
|
||||||
|
|
||||||
|
// let LE know that we're handling standalone / webroot here
|
||||||
|
var le = LE.create({
|
||||||
|
debug: args.debug
|
||||||
|
, server: args.server
|
||||||
|
, store: leStore
|
||||||
|
, challenge: leChallenge
|
||||||
|
, duplicate: args.duplicate
|
||||||
|
});
|
||||||
|
|
||||||
|
// Note: can't use args directly as null values will overwrite template values
|
||||||
|
le.register({
|
||||||
|
domains: args.domains
|
||||||
|
, email: args.email
|
||||||
|
, agreeTos: args.agreeTos
|
||||||
|
, challengeType: challengeType
|
||||||
|
, rsaKeySize: args.rsaKeySize
|
||||||
|
}).then(function (certs) {
|
||||||
|
if (servers) {
|
||||||
|
servers.closeServers();
|
||||||
|
}
|
||||||
|
|
||||||
|
// should get back account, path to certs, pems, etc?
|
||||||
|
console.log('\nCertificates installed at:');
|
||||||
|
console.log(Object.keys(args).filter(function (key) {
|
||||||
|
return /Path/.test(key);
|
||||||
|
}).map(function (key) {
|
||||||
|
return args[key];
|
||||||
|
}).join('\n').replace(/:hostname/, args.domains[0]));
|
||||||
|
|
||||||
|
console.log("");
|
||||||
|
console.log("Got certificate(s) for " + certs.altnames.join(', '));
|
||||||
|
console.log("\tIssued at " + new Date(certs.issuedAt).toISOString() + "");
|
||||||
|
console.log("\tValid until " + new Date(certs.expiresAt).toISOString() + "");
|
||||||
|
console.log("");
|
||||||
|
|
||||||
|
process.exit(0);
|
||||||
|
}, function (err) {
|
||||||
|
console.error('[Error]: letsencrypt-cli');
|
||||||
|
console.error(err.stack || new Error('get stack').stack);
|
||||||
|
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
|
@ -0,0 +1,89 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var NOBJ = {};
|
||||||
|
|
||||||
|
module.exports.create = function (challenge) {
|
||||||
|
var servers = {
|
||||||
|
_servers: []
|
||||||
|
|
||||||
|
, httpResponder: function (req, res) {
|
||||||
|
console.log('[LE-CLI] httpResponder');
|
||||||
|
var acmeChallengePrefix = '/.well-known/acme-challenge/';
|
||||||
|
|
||||||
|
if (0 !== req.url.indexOf(acmeChallengePrefix)) {
|
||||||
|
res.end("Let's Encrypt! Command line tool");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = req.url.slice(acmeChallengePrefix.length);
|
||||||
|
|
||||||
|
challenge.get(NOBJ, req.headers.host.replace(/:.*/, ''), token, function (err, val) {
|
||||||
|
res.end(val || '_ ERROR challenge not found _');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
, startServers: function (plainPorts, tlsPorts, opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
|
||||||
|
var httpsOptions = require('localhost.daplie.com-certificates');
|
||||||
|
var https = require('https');
|
||||||
|
var http = require('http');
|
||||||
|
|
||||||
|
if (servers._servers.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// http-01-port
|
||||||
|
plainPorts.forEach(function (port) {
|
||||||
|
var server = http.createServer(servers.httpResponder);
|
||||||
|
|
||||||
|
servers._servers.push(server);
|
||||||
|
server.listen(port, function () {
|
||||||
|
if (opts.debug) {
|
||||||
|
console.info('Listening http on', this.address());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
server.on('error', function (err) {
|
||||||
|
if ('EADDRINUSE' === err.code) {
|
||||||
|
console.error("");
|
||||||
|
console.error("You already have a different server running on port '" + port + "'.");
|
||||||
|
console.error("You should probably use the --webroot-path option instead of --standalone.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// tls-sni-01-port
|
||||||
|
tlsPorts.forEach(function (port) {
|
||||||
|
var server = https.createServer(httpsOptions, servers.httpResponder);
|
||||||
|
|
||||||
|
servers._servers.push(server);
|
||||||
|
servers.listen(port, function () {
|
||||||
|
if (opts.debug) {
|
||||||
|
console.info('Listening https on', this.address());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
servers.on('error', function (err) {
|
||||||
|
if ('EADDRINUSE' === err.code) {
|
||||||
|
console.error("");
|
||||||
|
console.error("You already have a different server running on port '" + port + "'.");
|
||||||
|
console.error("You should probably use the --webroot-path option instead of --standalone.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
, closeServers: function () {
|
||||||
|
servers._servers.forEach(function (server) {
|
||||||
|
server.close();
|
||||||
|
});
|
||||||
|
servers._servers = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return servers;
|
||||||
|
};
|
|
@ -1,75 +1,34 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
module.exports.create = function () {
|
module.exports.create = function (defaults) {
|
||||||
var handlers = {
|
var handlers = {
|
||||||
|
getOptions: function () {
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
//
|
//
|
||||||
// set,get,remove challenges
|
// set,get,remove challenges
|
||||||
//
|
//
|
||||||
// Note: this is fine for a one-off CLI tool
|
// Note: this is fine for a one-off CLI tool
|
||||||
// but a webserver using node-cluster or multiple
|
// but a webserver using node-cluster or multiple
|
||||||
// servers should use a database of some sort
|
// servers should use a database of some sort
|
||||||
_challenges: {}
|
, _challenges: {}
|
||||||
, setChallenge: function (args, key, value, cb) {
|
, set: function (args, domain, token, secret, cb) {
|
||||||
handlers._challenges[key] = value;
|
console.log('bloh 1');
|
||||||
|
handlers._challenges[token] = secret;
|
||||||
cb(null);
|
cb(null);
|
||||||
}
|
}
|
||||||
, getChallenge: function (args, key, cb) {
|
, get: function (args, domain, token, cb) {
|
||||||
|
console.log('bloh 2');
|
||||||
// TODO keep in mind that, generally get args are just args.domains
|
// TODO keep in mind that, generally get args are just args.domains
|
||||||
// and it is disconnected from the flow of setChallenge and removeChallenge
|
// and it is disconnected from the flow of setChallenge and removeChallenge
|
||||||
cb(null, handlers._challenges[key]);
|
cb(null, handlers._challenges[token]);
|
||||||
}
|
}
|
||||||
, removeChallenge: function (args, key, cb) {
|
, remove: function (args, domain, token, cb) {
|
||||||
delete handlers._challenges[key];
|
console.log('balh 3');
|
||||||
|
delete handlers._challenges[token];
|
||||||
cb(null);
|
cb(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
, _servers: []
|
|
||||||
, httpResponder: function (req, res) {
|
|
||||||
var acmeChallengePrefix = '/.well-known/acme-challenge/';
|
|
||||||
|
|
||||||
if (0 !== req.url.indexOf(acmeChallengePrefix)) {
|
|
||||||
res.end('Hello World!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = req.url.slice(acmeChallengePrefix.length);
|
|
||||||
|
|
||||||
handlers.getChallenge(req.headers.host, key, function (err, val) {
|
|
||||||
res.end(val || '_');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
, startServers: function (plainPorts, tlsPorts, opts) {
|
|
||||||
opts = opts || {};
|
|
||||||
var httpsOptions = require('localhost.daplie.com-certificates');
|
|
||||||
var https = require('https');
|
|
||||||
var http = require('http');
|
|
||||||
|
|
||||||
// tls-sni-01-port
|
|
||||||
if (handlers._servers.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
plainPorts.forEach(function (port) {
|
|
||||||
http.createServer(handlers.httpResponder).listen(port, function () {
|
|
||||||
if (opts.debug) {
|
|
||||||
console.info('Listening http on', this.address());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
tlsPorts.forEach(function (port) {
|
|
||||||
https.createServer(httpsOptions, handlers.httpResponder).listen(port, function () {
|
|
||||||
if (opts.debug) {
|
|
||||||
console.info('Listening https on', this.address());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
, closeServers: function () {
|
|
||||||
handlers._servers.forEach(function (server) {
|
|
||||||
server.close();
|
|
||||||
});
|
|
||||||
handlers._servers = [];
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return handlers;
|
return handlers;
|
||||||
|
|
|
@ -10,7 +10,7 @@ module.exports.create = function (defaults) {
|
||||||
// set,get,remove challenges
|
// set,get,remove challenges
|
||||||
//
|
//
|
||||||
getOptions: function () {
|
getOptions: function () {
|
||||||
return { webrootPath: defaults.webrootPath };
|
return defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
, set: function (args, domain, token, secret, cb) {
|
, set: function (args, domain, token, secret, cb) {
|
||||||
|
|
|
@ -35,8 +35,10 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cli": "^0.11.1",
|
"cli": "^0.11.1",
|
||||||
"homedir": "^0.6.0",
|
"homedir": "^0.6.0",
|
||||||
"letsencrypt": "^1.4.3",
|
"le-acme-core": "^2.0.5",
|
||||||
"localhost.daplie.com-certificates": "^1.1.2",
|
"le-store-certbot": "^2.0.2",
|
||||||
|
"letsencrypt": "^2.0.3",
|
||||||
|
"localhost.daplie.com-certificates": "^1.2.0",
|
||||||
"mkdirp": "^0.5.1"
|
"mkdirp": "^0.5.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue