replace apache with generic and extensible hooks
This commit is contained in:
parent
8b78ce694a
commit
5a1abb7e83
76
README.md
76
README.md
|
@ -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
|
||||
|
||||
|
|
|
@ -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/' ]
|
||||
|
|
53
index.js
53
index.js
|
@ -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) {
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue