replace apache with generic and extensible hooks

This commit is contained in:
Ben Schmidt 2016-10-12 02:22:37 +11:00
parent 8b78ce694a
commit 5a1abb7e83
4 changed files with 88 additions and 67 deletions

View File

@ -111,23 +111,22 @@ ls /etc/letsencrypt/live/
You can use a cron job to run the script above every 80 days (the certificates expire after 90 days)
so that you always have fresh certificates.
### TLS SNI (production option 2)
### Hooks (production option 2)
You can also integrate with a secure server. This is more complicated than the
webroot option, but it allows you to obtain certificates with only port 443
open. This facility was developed for the Apache webserver, but it could work
with other servers as long as they support server name indication (SNI) and you
can provide a configuration file template and hooks to install and uninstall it
(without downtime). In fact, it doesn't even need to be a webserver (though it
must run on port 443); it could be another server that performs SSL/TLS
negotiation with SNI.
open. This facility can work with any web server as long as it supports server
name indication (SNI) and you can provide a configuration file template and
shell hooks to install and uninstall the configuration (without downtime). In
fact, it doesn't even need to be a webserver (though it must run on port 443);
it could be another server that performs SSL/TLS negotiation with SNI.
The process works something like this. You would run:
```bash
sudo letsencrypt certonly \
--agree-tos --email john.doe@example.com \
--apache \
--hooks --hooks-server apache2-debian \
--config-dir /etc/letsencrypt \
--domains example.com,www.example.com \
--server https://acme-staging.api.letsencrypt.org/directory
@ -149,28 +148,32 @@ domain to prove you own the domain you're getting a certificate for.
After the domain has been validated externally, hooks are run to disable the
configuration fragment, and again check and reload the configuration.
Find your brand new certs in:
You can then find your brand new certs in:
```
ls /etc/letsencrypt/live/
```
To tailor this for your server setup, see all the `apache-` options in the list
below. Also note that the following substitutions are available for use in the
commands supplied to those options, and in any alternative template you
provide:
Tailor to your server and distro using the `--hooks-server` option. So far, the
following are supported (contributions for additional servers welcome):
* apache2-debian
To tweak it for your setup and taste, see all the `hooks-` options in the
Command Line Options section below. Also note that the following substitutions
are available for use in the hooks and the template:
* `{{{token}}}`: the token
* `{{{domain}}}`: the domain for which a certificate is being sought (beware of
this if using multiple domains per certificate)
* `{{{subject}}}`: the domain for which the generated challenge-fulfilling
certificate must be used (only available when generating it)
* `{{{cert}}}`: the path to the generated certificate: `apache-path/token.crt`
* `{{{privkey}}}`: the path to the generated private key: `apache-path/token.key`
* `{{{conf}}}`: the path to the generated config file: `apache-path/token.conf`
* `{{{bind}}}`: the value of the `apache-bind` option
* `{{{port}}}`: the value of the `apache-port` option
* `{{{webroot}}}`: the value of the `apache-webroot` option
* `{{{cert}}}`: the path to the generated certificate: `hooks-path/token.crt`
* `{{{privkey}}}`: the path to the generated private key: `hooks-path/token.key`
* `{{{conf}}}`: the path to the generated config file: `hooks-path/token.conf`
* `{{{bind}}}`: the value of the `hooks-bind` option
* `{{{port}}}`: the value of the `hooks-port` option
* `{{{webroot}}}`: the value of the `hooks-webroot` option
### Interactive (for debugging)
@ -230,7 +233,7 @@ you could change the permissions on them. **Probably a BAD IDEA**. Probabry a se
sudo chown -R $(whoami) /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt
```
## Command line Options
## Command Line Options
```
Usage:
@ -285,33 +288,34 @@ Options:
--webroot-path STRING public_html / webroot path.
--apache BOOLEAN Obtain certs using Apache virtual hosts.
--hooks BOOLEAN Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.
--apache-path STRING Path in which to store files for Apache virtual hosts.
--hooks-path STRING Path in which to store files for hooks.
(Default is ~/letsencrypt/apache)
--apache-bind [STRING] IP address to use for Apache virtual host. (Default is *)
(This is used in the default template.)
--hooks-server STRING Type of webserver to configure. Sets defaults for all the following --hooks- options.
Either --hooks-server or --hooks-template must be given.
(See the Hooks section above for a list of supported servers.)
--apache-port [NUMBER] Port to use for Apache virtual host. (Default is 443)
(This is used in the default template.)
--hooks-template STRING Template to use for hooks configuration file.
Either --hooks-server or --hooks-template must be given.
--apache-webroot STRING Webroot to use for Apache virtual host (e.g. an empty dir).
--hooks-bind STRING IP address to use in configuration for hooks. (Default is *)
--hooks-port STRING Port to use in configuration for hooks. (Default is 443)
--hooks-webroot STRING Webroot to use in configuration for hooks (e.g. empty dir).
Nothing should actually be served from here. (Default is /var/www)
--apache-template STRING Alternative template to use for Apache configuration file.
--hooks-pre-enable STRING Hook to check the webserver configuration prior to enabling.
--apache-enable STRING Command to run to enable the site in Apache.
(Default is `ln -s {{{conf}}} /etc/apache2/sites-enabled`)
--hooks-enable STRING Hook to enable the webserver configuration.
--apache-check STRING Command to run to check Apache configuration.
(Default is `apache2ctl configtest`)
--hooks-pre-reload STRING Hook to check the webserver configuration prior to reloading.
--apache-reload STRING Command to run to reload Apache.
(Default is `/etc/init.d/apache2 reload`)
--hooks-reload STRING Hook to reload the webserver.
--apache-disable STRING Command to run to disable the site in Apache.
(Default is `rm /etc/apache2/sites-enabled/{{{token}}}.conf`)
--hooks-disable STRING Hook to disable the webserver configuration.
--debug BOOLEAN show traces and logs

View File

@ -25,16 +25,18 @@ cli.parse({
, manual: [ false, " Print the token and key to the screen and wait for you to hit enter, giving you time to copy it somewhere before continuing (default: false)", 'boolean', false ]
, webroot: [ false, " Obtain certs by placing files in a webroot directory.", 'boolean', false ]
, 'webroot-path': [ false, " public_html / webroot path.", 'string' ]
, apache: [ false, " Obtain certs using Apache virtual hosts.", 'boolean', false ]
, 'apache-path': [ false, " Path in which to store files for Apache virtual hosts.", 'string' ]
, 'apache-bind': [ false, " IP address to use for Apache virtual host.", 'string', "*" ]
, 'apache-port': [ false, " Port to use for Apache virtual host.", 'int', 443 ]
, 'apache-webroot': [ false, " Webroot to use for Apache virtual host (e.g. empty dir).", 'string' ]
, 'apache-template': [ false, " Alternative template to use for Apache configuration file.", 'string' ]
, 'apache-enable': [ false, " Command to run to enable the site in Apache.", 'string' ]
, 'apache-check': [ false, " Command to run to check Apache configuration.", 'string' ]
, 'apache-reload': [ false, " Command to run to reload Apache.", 'string' ]
, 'apache-disable': [ false, " Command to run to disable the site in Apache.", 'string' ]
, hooks: [ false, " Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.", 'boolean', false ]
, 'hooks-path': [ false, " Path in which to store files for hooks.", 'string' ]
, 'hooks-server': [ false, " Type of webserver to configure.", 'string' ]
, 'hooks-template': [ false, " Template to use for hooks configuration file.", 'string' ]
, 'hooks-bind': [ false, " IP address to use in configuration for hooks.", 'string' ]
, 'hooks-port': [ false, " Port to use in configuration for hooks.", 'string' ]
, 'hooks-webroot': [ false, " Webroot to use in configuration for hooks (e.g. empty dir).", 'string' ]
, 'hooks-pre-enable': [ false, " Hook to check the webserver configuration prior to enabling.", 'string' ]
, 'hooks-enable': [ false, " Hook to enable the webserver configuration.", 'string' ]
, 'hooks-pre-reload': [ false, " Hook to check the webserver configuration prior to reloading.", 'string' ]
, 'hooks-reload': [ false, " Hook to reload the webserver.", 'string' ]
, 'hooks-disable': [ false, " Hook to disable the webserver configuration.", 'string' ]
//, 'standalone-supported-challenges': [ false, " Supported challenges, order preferences are randomly chosen. (default: http-01,tls-sni-01)", 'string', 'http-01,tls-sni-01']
, debug: [ false, " show traces and logs", 'boolean', false ]
, 'work-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/lib/' ]

View File

@ -15,7 +15,7 @@ module.exports.run = function (args) {
challengeType = 'dns-01';
args.webrootPath = '';
args.standalone = USE_DNS;
} else if (args.tlsSni01Port || args.apache) {
} else if (args.tlsSni01Port || args.hooks) {
challengeType = 'tls-sni-01';
args.webrootPath = '';
} else /*if (args.http01Port)*/ {
@ -25,17 +25,19 @@ module.exports.run = function (args) {
if (args.manual) {
leChallenge = require('le-challenge-manual').create({});
}
else if (args.apache) {
leChallenge = require('le-challenge-apache').create({
apachePath: args.apachePath
, apacheBind: args.apacheBind
, apachePort: args.apachePort
, apacheWebroot: args.apacheWebroot
, apacheTemplate: args.apacheTemplate
, apacheEnable: args.apacheEnable
, apacheCheck: args.apacheCheck
, apacheReload: args.apacheReload
, apacheDisable: args.apacheDisable
else if (args.hooks) {
leChallenge = require('le-challenge-hooks').create({
hooksPath: args.hooksPath
, hooksServer: args.hooksServer
, hooksTemplate: args.hooksTemplate
, hooksBind: args.hooksBind
, hooksPort: args.hooksPort
, hooksWebroot: args.hooksWebroot
, hooksPreEnable: args.hooksPreEnable
, hooksEnable: args.hooksEnable
, hooksPreReload: args.hooksPreReload
, hooksReload: args.hooksReload
, hooksDisable: args.hooksDisable
});
}
else if (args.webrootPath) {
@ -52,9 +54,10 @@ module.exports.run = function (args) {
servers = require('./lib/servers').create(leChallenge);
}
var privkeyPath = args.domainKeyPath || ':configDir/live/:hostname/privkey.pem'; //args.privkeyPath
leStore = require('le-store-certbot').create({
configDir: args.configDir
, privkeyPath: args.domainKeyPath || ':configDir/live/:hostname/privkey.pem' //args.privkeyPath
, privkeyPath: privkeyPath
, fullchainPath: args.fullchainPath
, certPath: args.certPath
, chainPath: args.chainPath
@ -123,14 +126,26 @@ module.exports.run = function (args) {
console.log("\tIssued at " + new Date(certs.issuedAt).toISOString() + "");
console.log("\tValid until " + new Date(certs.expiresAt).toISOString() + "");
console.log("");
console.log('Private key installed at:');
console.log(
privkeyPath
.replace(/:configDir/g, args.configDir)
.replace(/:hostname/g, args.domains[0])
);
console.log("");
// 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/g, args.domains[0]));
console.log('Certificates installed at:');
console.log(
[
args.certPath
, args.chainPath
, args.fullchainPath
].join('\n')
.replace(/:configDir/g, args.configDir)
.replace(/:hostname/g, args.domains[0])
);
console.log("");
process.exit(0);
}, function (err) {

View File

@ -36,12 +36,12 @@
"cli": "^0.11.1",
"homedir": "^0.6.0",
"le-acme-core": "^2.0.5",
"le-challenge-apache": "^2.0.1",
"le-challenge-hooks": "^2.0.0",
"le-challenge-manual": "^2.0.0",
"le-challenge-sni": "^2.0.0",
"le-challenge-standalone": "^2.0.0",
"le-store-certbot": "^2.0.2",
"letsencrypt": "^2.1.2",
"letsencrypt": "^2.1.8",
"localhost.daplie.com-certificates": "^1.2.0",
"mkdirp": "^0.5.1"
}