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)
|
||||
|
||||
| [letsencrypt (library)](https://github.com/Daplie/node-letsencrypt)
|
||||
| **letsencrypt-cli**
|
||||
| **letsencrypt-cli**
|
||||
| [letsencrypt-express](https://github.com/Daplie/letsencrypt-express)
|
||||
| [letsencrypt-koa](https://github.com/Daplie/letsencrypt-koa)
|
||||
| [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
|
||||
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
|
||||
|
@ -159,10 +159,13 @@ Options:
|
|||
|
||||
--debug BOOLEAN show traces and logs
|
||||
|
||||
--tls-sni-01-port NUMBER Port number to perform tls-sni-01 challenge.
|
||||
Boulder in testing mode defaults to 5001. (default: 443 and 5001)
|
||||
--tls-sni-01-port NUMBER Use TLS-SNI-01 challenge type with this port. (Default is 443)
|
||||
(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)
|
||||
|
||||
|
|
|
@ -10,13 +10,15 @@ cli.parse({
|
|||
, 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 ]
|
||||
, 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' ]
|
||||
, 'http-01-port': [ false, " Port used in the SimpleHttp challenge. (default: 80)", '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, " 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 ]
|
||||
, 'cert-path': [ false, " Path to where new cert.pem is saved", 'string',':config/live/:hostname/cert.pem' ]
|
||||
, 'fullchain-path': [ false, " Path to where new fullchain.pem (cert + chain) is saved", 'string', ':config/live/:hostname/fullchain.pem' ]
|
||||
, 'chain-path': [ false, " Path to where new chain.pem is saved", 'string', ':config/live/:hostname/chain.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', ':configDir/live/:hostname/fullchain.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' ]
|
||||
, 'account-key-path': [ false, " Path to privkey.pem to use for account (default: generate new)", 'string' ]
|
||||
, 'config-dir': [ false, " Configuration directory.", 'string', '~/letsencrypt/etc/' ]
|
||||
, server: [ false, " ACME Directory Resource URI.", 'string', 'https://acme-v01.api.letsencrypt.org/directory)' ]
|
||||
, standalone: [ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ]
|
||||
|
@ -49,7 +51,7 @@ cli.main(function(_, options) {
|
|||
var val = args[key];
|
||||
|
||||
if ('string' === typeof val) {
|
||||
val = val.replace(/\:config/, args.configDir);
|
||||
val = val.replace(/(\:configDir)|(\:config)/, args.configDir);
|
||||
}
|
||||
|
||||
args[key] = val;
|
||||
|
@ -88,54 +90,6 @@ cli.main(function(_, options) {
|
|||
return;
|
||||
}
|
||||
|
||||
var LE = require('letsencrypt');
|
||||
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);
|
||||
});
|
||||
require('../').run(args);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/bin/bash
|
||||
|
||||
letsencrypt certonly \
|
||||
--agree-tos --email coolaj86+le.1010@gmail.com \
|
||||
node bin/letsencrypt certonly \
|
||||
--agree-tos --email 'coolaj86+le.1010@gmail.com' \
|
||||
--standalone \
|
||||
--domains pokemap.hellabit.com,www.pokemap.hellabit.com \
|
||||
--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';
|
||||
|
||||
module.exports.create = function () {
|
||||
module.exports.create = function (defaults) {
|
||||
var handlers = {
|
||||
getOptions: function () {
|
||||
return defaults;
|
||||
}
|
||||
//
|
||||
// set,get,remove challenges
|
||||
//
|
||||
// Note: this is fine for a one-off CLI tool
|
||||
// but a webserver using node-cluster or multiple
|
||||
// servers should use a database of some sort
|
||||
_challenges: {}
|
||||
, setChallenge: function (args, key, value, cb) {
|
||||
handlers._challenges[key] = value;
|
||||
, _challenges: {}
|
||||
, set: function (args, domain, token, secret, cb) {
|
||||
console.log('bloh 1');
|
||||
handlers._challenges[token] = secret;
|
||||
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
|
||||
// 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) {
|
||||
delete handlers._challenges[key];
|
||||
, remove: function (args, domain, token, cb) {
|
||||
console.log('balh 3');
|
||||
delete handlers._challenges[token];
|
||||
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;
|
||||
|
|
|
@ -10,7 +10,7 @@ module.exports.create = function (defaults) {
|
|||
// set,get,remove challenges
|
||||
//
|
||||
getOptions: function () {
|
||||
return { webrootPath: defaults.webrootPath };
|
||||
return defaults;
|
||||
}
|
||||
|
||||
, set: function (args, domain, token, secret, cb) {
|
||||
|
|
|
@ -35,8 +35,10 @@
|
|||
"dependencies": {
|
||||
"cli": "^0.11.1",
|
||||
"homedir": "^0.6.0",
|
||||
"letsencrypt": "^1.4.3",
|
||||
"localhost.daplie.com-certificates": "^1.1.2",
|
||||
"le-acme-core": "^2.0.5",
|
||||
"le-store-certbot": "^2.0.2",
|
||||
"letsencrypt": "^2.0.3",
|
||||
"localhost.daplie.com-certificates": "^1.2.0",
|
||||
"mkdirp": "^0.5.1"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue