Compare commits

..

No commits in common. "master" and "v2.0.5" have entirely different histories.

5 changed files with 62 additions and 187 deletions

View File

@ -1,39 +1,7 @@
# Deprecated le-store-certbot
================
`le-store-certbot` has been replaced with [`le-store-fs`](https://git.coolaj86.com/coolaj86/le-store-fs.js). The "certbot" storage strategy for node-letsencrypt.
The new storage strategy **keeps file system compatibility**, but **drops support** for Python config files.
Unless you're running `certbot` and Greenlock side-by-side, or interchangeably, you switch to `le-store-fs`.
## Migrating to `le-store-fs`
It's **painless** and all of your existing certificates will be **preserved**
(assuming you use the same `configDir` as before).
```js
Greenlock.create({
// Leave configDir as it, if you've been setting it yourself.
// Otherwise you should explicitly set it to the previous default:
configDir: '~/letsencrypt/etc'
// le-store-fs takes the same options as le-store-certbot,
// but ignores some of the ones that aren't important.
, store: require('le-store-fs').create({})
...
})
```
## Alternatives
* Search npm for ["le-store-"](https://www.npmjs.com/search?q=le-store-) to find many alternatives.
# le-store-certbot
The "certbot" storage strategy for
[Greenlock.js](https://git.coolaj86.com/coolaj86/le-store-certbot.js).
This le storage strategy aims to maintain compatibility with the This le storage strategy aims to maintain compatibility with the
configuration files and file structure of the official certbot client. configuration files and file structure of the official certbot client.
@ -49,27 +17,24 @@ npm install --save le-store-certbot@2.x
```bash ```bash
var leStore = require('le-store-certbot').create({ var leStore = require('le-store-certbot').create({
configDir: require('homedir')() + '/acme/etc' // or /etc/acme or wherever configDir: require('homedir')() + '/letsencrypt/etc' // or /etc/letsencrypt or wherever
, privkeyPath: ':configDir/live/:hostname/privkey.pem' // , privkeyPath: ':configDir/live/:hostname/privkey.pem' //
, fullchainPath: ':configDir/live/:hostname/fullchain.pem' // Note: both that :configDir and :hostname , fullchainPath: ':configDir/live/:hostname/fullchain.pem' // Note: both that :configDir and :hostname
, certPath: ':configDir/live/:hostname/cert.pem' // will be templated as expected by , certPath: ':configDir/live/:hostname/cert.pem' // will be templated as expected by
, chainPath: ':configDir/live/:hostname/chain.pem' // greenlock.js , chainPath: ':configDir/live/:hostname/chain.pem' // node-letsencrypt
, logsDir: require('homedir')() + '/tmp/acme/log' , workDir: require('homedir')() + '/letsencrypt/var/lib'
, logsDir: require('homedir')() + '/letsencrypt/var/log'
, webrootPath: '~/acme/srv/www/:hostname/.well-known/acme-challenge' , webrootPath: '~/letsencrypt/srv/www/:hostname/.well-known/acme-challenge'
, debug: false , debug: false
}); });
```
The store module can be used globally with Greenlock like this: var LE = require('letsencrypt');
``` LE.create({
var Greenlock = require('greenlock'); server: LE.stagingServerUrl // Change to LE.productionServerUrl in production
Greenlock.create({
...
, store: leStore , store: leStore
}); });
``` ```
@ -78,7 +43,7 @@ Example File Structure
---------------------- ----------------------
``` ```
~/acme/ ~/letsencrypt/
└── etc └── etc
├── accounts ├── accounts
│   └── acme-staging.api.letsencrypt.org │   └── acme-staging.api.letsencrypt.org
@ -88,19 +53,19 @@ Example File Structure
│   ├── private_key.json │   ├── private_key.json
│   └── regr.json │   └── regr.json
├── archive ├── archive
│   └── example.com │   └── example.daplie.me
│   ├── cert0.pem │   ├── cert0.pem
│   ├── chain0.pem │   ├── chain0.pem
│   ├── fullchain0.pem │   ├── fullchain0.pem
│   └── privkey0.pem │   └── privkey0.pem
├── live ├── live
│   └── example.com │   └── example.daplie.me
│   ├── cert.pem │   ├── cert.pem
│   ├── chain.pem │   ├── chain.pem
│   ├── fullchain.pem │   ├── fullchain.pem
│   ├── privkey.pem │   ├── privkey.pem
│   └── privkey.pem.bak │   └── privkey.pem.bak
└── renewal └── renewal
├── example.com.conf ├── example.daplie.me.conf
└── example.com.conf.bak └── example.daplie.me.conf.bak
``` ```

114
index.js
View File

@ -1,30 +1,9 @@
'use strict'; 'use strict';
/* global Promise */
var PromiseA; var PromiseA = require('bluebird');
try { var mkdirpAsync = PromiseA.promisify(require('mkdirp'));
PromiseA = require('bluebird');
} catch(e) {
PromiseA = Promise;
}
var util = require('util');
if (!util.promisify) {
util.promisify = PromiseA.promisify;
}
function promisifyAll(obj) {
var aobj = {};
Object.keys(obj).forEach(function (key) {
aobj[key + 'Async'] = util.promisify(obj[key]);
});
return aobj;
}
var mkdirpAsync = util.promisify(require('@root/mkdirp'));
var path = require('path'); var path = require('path');
var fs = require('fs'); var fs = PromiseA.promisifyAll(require('fs'));
var readFileAsync = util.promisify(fs.readFile);
var readdirAsync = util.promisify(fs.readdir);
var writeFileAsync = util.promisify(fs.writeFile);
var statAsync = util.promisify(fs.stat);
var sfs = require('safe-replace'); var sfs = require('safe-replace');
var os = require('os'); var os = require('os');
@ -41,7 +20,7 @@ function writeRenewalConfig(args) {
var pyobj = args.pyobj; var pyobj = args.pyobj;
pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0; pyobj.checkpoints = parseInt(pyobj.checkpoints, 10) || 0;
var pyconf = promisifyAll(require('pyconf')); var pyconf = PromiseA.promisifyAll(require('pyconf'));
var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]); var liveDir = args.liveDir || path.join(args.configDir, 'live', args.domains[0]);
@ -121,12 +100,10 @@ function pyToJson(pyobj) {
return jsobj; return jsobj;
} }
var crypto = require('crypto');
var rnd = crypto.randomBytes(8).toString('hex');
var defaults = { var defaults = {
configDir: [ os.homedir(), 'letsencrypt', 'etc' ].join(path.sep) // /etc/letsencrypt/ configDir: [ os.homedir(), 'letsencrypt', 'etc' ].join(path.sep) // /etc/letsencrypt/
, logsDir: [ os.tmpdir(), 'acme-' + rnd, 'log' ].join(path.sep) // /var/log/letsencrypt/ , logsDir: [ os.homedir(), 'letsencrypt', 'var', 'log' ].join(path.sep) // /var/log/letsencrypt/
, webrootPath: [ os.tmpdir(), 'acme-' + rnd, 'acme-challenge' ].join(path.sep) , workDir: [ os.homedir(), 'letsencrypt', 'var', 'lib' ].join(path.sep) // /var/lib/letsencrypt/
, accountsDir: [ ':configDir', 'accounts', ':serverDir' ].join(path.sep) , accountsDir: [ ':configDir', 'accounts', ':serverDir' ].join(path.sep)
, renewalPath: [ ':configDir', 'renewal', ':hostname.conf' ].join(path.sep) , renewalPath: [ ':configDir', 'renewal', ':hostname.conf' ].join(path.sep)
@ -139,9 +116,9 @@ var defaults = {
, fullchainPath: [ ':configDir', 'live', ':hostname', 'fullchain.pem' ].join(path.sep) , fullchainPath: [ ':configDir', 'live', ':hostname', 'fullchain.pem' ].join(path.sep)
, certPath: [ ':configDir', 'live', ':hostname', 'cert.pem' ].join(path.sep) , certPath: [ ':configDir', 'live', ':hostname', 'cert.pem' ].join(path.sep)
, chainPath: [ ':configDir', 'live', ':hostname', 'chain.pem' ].join(path.sep) , chainPath: [ ':configDir', 'live', ':hostname', 'chain.pem' ].join(path.sep)
, bundlePath: [ ':configDir', 'live', ':hostname', 'bundle.pem' ].join(path.sep)
, rsaKeySize: 2048 , rsaKeySize: 2048
, webrootPath: [ ':workDir', 'acme-challenge' ].join(path.sep)
}; };
module.exports.create = function (configs) { module.exports.create = function (configs) {
@ -172,7 +149,7 @@ module.exports.create = function (configs) {
if (!keypath) { if (!keypath) {
return null; return null;
} }
return readFileAsync(keypath, 'ascii').then(function (key) { return fs.readFileAsync(keypath, 'ascii').then(function (key) {
if ('jwk' === format) { if ('jwk' === format) {
return { privateKeyJwk: JSON.parse(key) }; return { privateKeyJwk: JSON.parse(key) };
} }
@ -198,7 +175,7 @@ module.exports.create = function (configs) {
key = keypair.privateKeyPem; key = keypair.privateKeyPem;
} }
return writeFileAsync(keypath, key, 'ascii').then(function () { return fs.writeFileAsync(keypath, key, 'ascii').then(function () {
return keypair; return keypair;
}); });
}); });
@ -227,15 +204,15 @@ module.exports.create = function (configs) {
return PromiseA.reject(new Error("missing one or more of privkeyPath, fullchainPath, certPath, chainPath from options")); return PromiseA.reject(new Error("missing one or more of privkeyPath, fullchainPath, certPath, chainPath from options"));
} }
//, readFileAsync(fullchainPath, 'ascii') //, fs.readFileAsync(fullchainPath, 'ascii')
// note: if this ^^ gets added back in, the arrays below must change // note: if this ^^ gets added back in, the arrays below must change
return PromiseA.all([ return PromiseA.all([
readFileAsync(args.privkeyPath, 'ascii') // 0 fs.readFileAsync(args.privkeyPath, 'ascii') // 0
, readFileAsync(args.certPath, 'ascii') // 1 , fs.readFileAsync(args.certPath, 'ascii') // 1
, readFileAsync(args.chainPath, 'ascii') // 2 , fs.readFileAsync(args.chainPath, 'ascii') // 2
// stat the file, not the link // stat the file, not the link
, statAsync(args.certPath) // 3 , fs.statAsync(args.certPath) // 3
]).then(function (arr) { ]).then(function (arr) {
return { return {
privkey: arr[0] // privkey.pem privkey: arr[0] // privkey.pem
@ -249,8 +226,8 @@ module.exports.create = function (configs) {
}; };
}, function (err) { }, function (err) {
if (args.debug) { if (args.debug) {
log("certificates.check"); console.error("[le-store-certbot] certificates.check");
log(err.stack); console.error(err.stack);
} }
return null; return null;
}); });
@ -267,8 +244,9 @@ module.exports.create = function (configs) {
var certPath = args.certPath || pyobj.cert || path.join(liveDir, 'cert.pem'); var certPath = args.certPath || pyobj.cert || path.join(liveDir, 'cert.pem');
var fullchainPath = args.fullchainPath || pyobj.fullchain || path.join(liveDir, 'fullchain.pem'); var fullchainPath = args.fullchainPath || pyobj.fullchain || path.join(liveDir, 'fullchain.pem');
var chainPath = args.chainPath || pyobj.chain || path.join(liveDir, 'chain.pem'); var chainPath = args.chainPath || pyobj.chain || path.join(liveDir, 'chain.pem');
var privkeyPath = args.privkeyPath || pyobj.privkey || args.domainKeyPath || path.join(liveDir, 'privkey.pem'); var privkeyPath = args.privkeyPath || pyobj.privkey
var bundlePath = args.bundlePath || pyobj.bundle || path.join(liveDir, 'bundle.pem'); || args.domainKeyPath
|| path.join(liveDir, 'privkey.pem');
var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]); var archiveDir = args.archiveDir || path.join(args.configDir, 'archive', args.domains[0]);
@ -277,31 +255,22 @@ module.exports.create = function (configs) {
var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoints + '.pem'); var fullchainArchive = path.join(archiveDir, 'fullchain' + checkpoints + '.pem');
var chainArchive = path.join(archiveDir, 'chain'+ checkpoints + '.pem'); var chainArchive = path.join(archiveDir, 'chain'+ checkpoints + '.pem');
var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoints + '.pem'); var privkeyArchive = path.join(archiveDir, 'privkey' + checkpoints + '.pem');
var bundleArchive = path.join(archiveDir, 'bundle' + checkpoints + '.pem');
return mkdirpAsync(archiveDir).then(function () { return mkdirpAsync(archiveDir).then(function () {
var ps = [ return PromiseA.all([
sfs.writeFileAsync(certArchive, pems.cert, 'ascii') sfs.writeFileAsync(certArchive, pems.cert, 'ascii')
, sfs.writeFileAsync(chainArchive, pems.chain, 'ascii') , sfs.writeFileAsync(chainArchive, pems.chain, 'ascii')
, sfs.writeFileAsync(fullchainArchive, [ pems.cert, pems.chain ].join('\n'), 'ascii') , sfs.writeFileAsync(fullchainArchive, pems.cert + pems.chain, 'ascii')
, sfs.writeFileAsync(privkeyArchive, pems.privkey, 'ascii') , sfs.writeFileAsync(privkeyArchive, pems.privkey, 'ascii')
]; ]);
if (pems.bundle) {
var bundleP = sfs.writeFileAsync(bundleArchive, pems.bundle, 'ascii');
ps.push(bundleP);
}
return PromiseA.all(ps);
}).then(function () { }).then(function () {
return mkdirpAsync(liveDir); return mkdirpAsync(liveDir);
}).then(function () { }).then(function () {
return PromiseA.all([ return PromiseA.all([
sfs.writeFileAsync(certPath, pems.cert, 'ascii') sfs.writeFileAsync(certPath, pems.cert, 'ascii')
, sfs.writeFileAsync(chainPath, pems.chain, 'ascii') , sfs.writeFileAsync(chainPath, pems.chain, 'ascii')
// Most platforms need these two , sfs.writeFileAsync(fullchainPath, pems.cert + pems.chain, 'ascii')
, sfs.writeFileAsync(fullchainPath, [ pems.cert, pems.chain ].join('\n'), 'ascii')
, sfs.writeFileAsync(privkeyPath, pems.privkey, 'ascii') , sfs.writeFileAsync(privkeyPath, pems.privkey, 'ascii')
// HAProxy needs "bundle.pem" aka "combined.pem"
, sfs.writeFileAsync(bundlePath, [ pems.privkey, pems.cert, pems.chain ].join('\n'), 'ascii')
]); ]);
}).then(function () { }).then(function () {
pyobj.checkpoints += 1; pyobj.checkpoints += 1;
@ -315,8 +284,6 @@ module.exports.create = function (configs) {
privkey: pems.privkey privkey: pems.privkey
, cert: pems.cert , cert: pems.cert
, chain: pems.chain , chain: pems.chain
, expires: pems.expires
, identifiers: pems.identifiers
/* /*
// TODO populate these only if they are actually known // TODO populate these only if they are actually known
@ -361,11 +328,11 @@ module.exports.create = function (configs) {
log(args.debug, "No email given"); log(args.debug, "No email given");
return PromiseA.resolve(null); return PromiseA.resolve(null);
} }
return readdirAsync(args.accountsDir).then(function (nodes) { return fs.readdirAsync(args.accountsDir).then(function (nodes) {
log(args.debug, "success reading arg.accountsDir"); log(args.debug, "success reading arg.accountsDir");
return PromiseA.all(nodes.map(function (node) { return PromiseA.all(nodes.map(function (node) {
return readFileAsync(path.join(args.accountsDir, node, 'regr.json'), 'utf8').then(function (text) { return fs.readFileAsync(path.join(args.accountsDir, node, 'regr.json'), 'utf8').then(function (text) {
var regr = JSON.parse(text); var regr = JSON.parse(text);
regr.__accountId = node; regr.__accountId = node;
@ -406,8 +373,7 @@ module.exports.create = function (configs) {
// Accounts // Accounts
, _getAccountIdByPublicKey: function (keypair) { , _getAccountIdByPublicKey: function (keypair) {
// we use insecure md5 - even though we know it's bad - because that's how the python client did // we use insecure md5 - even though we know it's bad - because that's how the python client did
var pubkey = keypair.publicKeyPem.replace(/\r/g, ''); return require('crypto').createHash('md5').update(keypair.publicKeyPem).digest('hex');
return crypto.createHash('md5').update(pubkey).digest('hex');
} }
// Accounts // Accounts
, checkKeypairAsync: function (args) { , checkKeypairAsync: function (args) {
@ -463,7 +429,7 @@ module.exports.create = function (configs) {
return PromiseA.all(configs.map(function (filename) { return PromiseA.all(configs.map(function (filename) {
var keyname = filename.slice(0, -5); var keyname = filename.slice(0, -5);
return readFileAsync(path.join(accountDir, filename), 'utf8').then(function (text) { return fs.readFileAsync(path.join(accountDir, filename), 'utf8').then(function (text) {
var data; var data;
try { try {
@ -515,25 +481,15 @@ module.exports.create = function (configs) {
creation_host: os.hostname() creation_host: os.hostname()
, creation_dt: new Date().toISOString() , creation_dt: new Date().toISOString()
}; };
var uri = args.server.replace(/\/directory.*/,
'/acme/reg/' + accountId);
return mkdirpAsync(accountDir).then(function () { return mkdirpAsync(accountDir).then(function () {
var regrBody = {
body: reg.receipt,
uri: uri,
};
if (typeof reg.newAuthzUrl !== 'undefined') {
regrBody.new_authzr_uri = reg.newAuthzUrl;
}
// TODO abstract file writing // TODO abstract file writing
return PromiseA.all([ return PromiseA.all([
// meta.json {"creation_host": "ns1.redirect-www.org", "creation_dt": "2015-12-11T04:14:38Z"} // meta.json {"creation_host": "ns1.redirect-www.org", "creation_dt": "2015-12-11T04:14:38Z"}
writeFileAsync(path.join(accountDir, 'meta.json'), JSON.stringify(accountMeta), 'utf8') fs.writeFileAsync(path.join(accountDir, 'meta.json'), JSON.stringify(accountMeta), 'utf8')
// private_key.json { "e", "d", "n", "q", "p", "kty", "qi", "dp", "dq" } // private_key.json { "e", "d", "n", "q", "p", "kty", "qi", "dp", "dq" }
, writeFileAsync(path.join(accountDir, 'private_key.json'), JSON.stringify(reg.keypair.privateKeyJwk), 'utf8') , fs.writeFileAsync(path.join(accountDir, 'private_key.json'), JSON.stringify(reg.keypair.privateKeyJwk), 'utf8')
// regr.json: // regr.json:
/* /*
{ body: { contact: [ 'mailto:coolaj86@gmail.com' ], { body: { contact: [ 'mailto:coolaj86@gmail.com' ],
@ -543,9 +499,7 @@ module.exports.create = function (configs) {
new_authzr_uri: 'https://acme-v01.api.letsencrypt.org/acme/new-authz', new_authzr_uri: 'https://acme-v01.api.letsencrypt.org/acme/new-authz',
terms_of_service: 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf' } terms_of_service: 'https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf' }
*/ */
, writeFileAsync(path.join(accountDir, 'regr.json'), , fs.writeFileAsync(path.join(accountDir, 'regr.json'), JSON.stringify({ body: reg.receipt }), 'utf8')
JSON.stringify(regrBody),
'utf8')
]); ]);
}).then(function () { }).then(function () {
return { return {
@ -559,7 +513,7 @@ module.exports.create = function (configs) {
} }
// Accounts // Accounts
, getAccountIdAsync: function (args) { , getAccountIdAsync: function (args) {
var pyconf = promisifyAll(require('pyconf')); var pyconf = PromiseA.promisifyAll(require('pyconf'));
return pyconf.readFileAsync(args.renewalPath).then(function (renewal) { return pyconf.readFileAsync(args.renewalPath).then(function (renewal) {
var accountId = renewal.account; var accountId = renewal.account;
@ -595,7 +549,7 @@ module.exports.create = function (configs) {
} }
// Configs // Configs
, _checkHelperAsync: function (args) { , _checkHelperAsync: function (args) {
var pyconf = promisifyAll(require('pyconf')); var pyconf = PromiseA.promisifyAll(require('pyconf'));
return pyconf.readFileAsync(args.renewalPath).then(function (pyobj) { return pyconf.readFileAsync(args.renewalPath).then(function (pyobj) {
return pyobj; return pyobj;
@ -649,7 +603,7 @@ module.exports.create = function (configs) {
, allAsync: function (copy) { , allAsync: function (copy) {
copy.domains = []; copy.domains = [];
return readdirAsync(copy.renewalDir).then(function (nodes) { return fs.readdirAsync(copy.renewalDir).then(function (nodes) {
nodes = nodes.filter(function (node) { nodes = nodes.filter(function (node) {
return /^[a-z0-9]+.*\.conf$/.test(node); return /^[a-z0-9]+.*\.conf$/.test(node);
}); });

26
package-lock.json generated
View File

@ -1,26 +0,0 @@
{
"name": "le-store-certbot",
"version": "2.2.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@root/mkdirp": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@root/mkdirp/-/mkdirp-1.0.0.tgz",
"integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA=="
},
"pyconf": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/pyconf/-/pyconf-1.1.7.tgz",
"integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==",
"requires": {
"safe-replace": "^1.0.2"
}
},
"safe-replace": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-replace/-/safe-replace-1.1.0.tgz",
"integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw=="
}
}
}

View File

@ -1,15 +1,14 @@
{ {
"name": "le-store-certbot", "name": "le-store-certbot",
"version": "2.2.4", "version": "2.0.5",
"description": "The \"certbot\" storage strategy for Greenlock.js", "description": "The \"certbot\" storage strategy for node-letsencrypt",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"bump": "npm version -m \"chore(release): bump to v%s\"",
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js" "url": "git+https://github.com/Daplie/le-store-certbot.git"
}, },
"keywords": [ "keywords": [
"le-store", "le-store",
@ -21,15 +20,13 @@
"author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)", "author": "AJ ONeal <coolaj86@gmail.com> (https://coolaj86.com/)",
"license": "(MIT OR Apache-2.0)", "license": "(MIT OR Apache-2.0)",
"bugs": { "bugs": {
"url": "https://git.coolaj86.com/coolaj86/le-store-certbot.js/issues" "url": "https://github.com/Daplie/le-store-certbot/issues"
},
"homepage": "https://git.coolaj86.com/coolaj86/le-store-certbot.js",
"trulyOptionalDependencies": {
"bluebird": "^3.5.1"
}, },
"homepage": "https://github.com/Daplie/le-store-certbot#readme",
"dependencies": { "dependencies": {
"@root/mkdirp": "^1.0.0", "bluebird": "^3.4.1",
"pyconf": "^1.1.7", "mkdirp": "^0.5.1",
"safe-replace": "^1.1.0" "pyconf": "^1.1.2",
"safe-replace": "^1.0.2"
} }
} }

View File

@ -6,78 +6,63 @@ fullchain = :fullchain_path
# Options and defaults used in the renewal process # Options and defaults used in the renewal process
[renewalparams] [renewalparams]
no_self_upgrade = True
apache_enmod = a2enmod apache_enmod = a2enmod
no_verify_ssl = False no_verify_ssl = False
ifaces = None ifaces = None
apache_dismod = a2dismod apache_dismod = a2dismod
register_unsafely_without_email = False register_unsafely_without_email = False
apache_handle_modules = True
uir = None uir = None
installer = None installer = none
nginx_ctl = nginx
config_dir = :configDir config_dir = :configDir
text_mode = True text_mode = True
# junk? # junk?
# https://github.com/letsencrypt/letsencrypt/issues/1955 # https://github.com/letsencrypt/letsencrypt/issues/1955
func = <function obtain_cert at 0x7f093a163c08> func = <function obtain_cert at 0x30c9500>
staging = False
prepare = False prepare = False
work_dir = :work_dir work_dir = :work_dir
tos = :agree_tos tos = :agree_tos
init = False init = False
http01_port = :http_01_port http01_port = :http_01_port
duplicate = False duplicate = False
noninteractive_mode = True
# this is for the domain # this is for the domain
key_path = :privkey_path key_path = :privkey_path
nginx = False nginx = False
nginx_server_root = /etc/nginx
fullchain_path = :fullchain_path fullchain_path = :fullchain_path
email = :email email = :email
csr = None csr = None
agree_dev_preview = None agree_dev_preview = None
redirect = None redirect = None
verb = certonly
verbose_count = -3 verbose_count = -3
config_file = None config_file = None
renew_by_default = True renew_by_default = True
hsts = False hsts = False
apache_handle_sites = True
authenticator = webroot authenticator = webroot
domains = :hostnames #comma,delimited,list domains = :hostnames #comma,delimited,list
rsa_key_size = :rsa_key_size rsa_key_size = :rsa_key_size
apache_challenge_location = /etc/apache2
# starts at 0 and increments at every renewal # starts at 0 and increments at every renewal
checkpoints = -1 checkpoints = -1
manual_test_mode = False manual_test_mode = False
apache = False apache = False
cert_path = :cert_path cert_path = :cert_path
webroot_path = :webroot_paths # comma,delimited,list webroot_path = :webroot_paths # comma,delimited,list
reinstall = False
expand = False
strict_permissions = False strict_permissions = False
apache_server_root = /etc/apache2 apache_server_root = /etc/apache2
# https://github.com/letsencrypt/letsencrypt/issues/1948 # https://github.com/letsencrypt/letsencrypt/issues/1948
account = :account_id account = :account_id
dry_run = False
manual_public_ip_logging_ok = False manual_public_ip_logging_ok = False
chain_path = :chain_path chain_path = :chain_path
break_my_certs = False
standalone = False standalone = False
manual = False manual = False
server = :acme_discovery_url server = :acme_discovery_url
standalone_supported_challenges = "http-01,tls-sni-01" standalone_supported_challenges = "http-01,tls-sni-01"
webroot = True webroot = True
os_packages_only = False
apache_init_script = None apache_init_script = None
user_agent = None user_agent = None
apache_ctl = apache2ctl
apache_le_vhost_ext = -le-ssl.conf apache_le_vhost_ext = -le-ssl.conf
debug = False debug = False
tls_sni_01_port = 443 tls_sni_01_port = 443
logs_dir = :logs_dir logs_dir = :logs_dir
apache_vhost_root = /etc/apache2/sites-available
configurator = None configurator = None
must_staple = False
[[webroot_map]] [[webroot_map]]
# :hostname = :webroot_path # :hostname = :webroot_path