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)
|
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.
|
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
|
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
|
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
|
open. This facility can work with any web server as long as it supports server
|
||||||
with other servers as long as they support server name indication (SNI) and you
|
name indication (SNI) and you can provide a configuration file template and
|
||||||
can provide a configuration file template and hooks to install and uninstall it
|
shell hooks to install and uninstall the configuration (without downtime). In
|
||||||
(without downtime). In fact, it doesn't even need to be a webserver (though it
|
fact, it doesn't even need to be a webserver (though it must run on port 443);
|
||||||
must run on port 443); it could be another server that performs SSL/TLS
|
it could be another server that performs SSL/TLS negotiation with SNI.
|
||||||
negotiation with SNI.
|
|
||||||
|
|
||||||
The process works something like this. You would run:
|
The process works something like this. You would run:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo letsencrypt certonly \
|
sudo letsencrypt certonly \
|
||||||
--agree-tos --email john.doe@example.com \
|
--agree-tos --email john.doe@example.com \
|
||||||
--apache \
|
--hooks --hooks-server apache2-debian \
|
||||||
--config-dir /etc/letsencrypt \
|
--config-dir /etc/letsencrypt \
|
||||||
--domains example.com,www.example.com \
|
--domains example.com,www.example.com \
|
||||||
--server https://acme-staging.api.letsencrypt.org/directory
|
--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
|
After the domain has been validated externally, hooks are run to disable the
|
||||||
configuration fragment, and again check and reload the configuration.
|
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/
|
ls /etc/letsencrypt/live/
|
||||||
```
|
```
|
||||||
|
|
||||||
To tailor this for your server setup, see all the `apache-` options in the list
|
Tailor to your server and distro using the `--hooks-server` option. So far, the
|
||||||
below. Also note that the following substitutions are available for use in the
|
following are supported (contributions for additional servers welcome):
|
||||||
commands supplied to those options, and in any alternative template you
|
|
||||||
provide:
|
* 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
|
* `{{{token}}}`: the token
|
||||||
* `{{{domain}}}`: the domain for which a certificate is being sought (beware of
|
* `{{{domain}}}`: the domain for which a certificate is being sought (beware of
|
||||||
this if using multiple domains per certificate)
|
this if using multiple domains per certificate)
|
||||||
* `{{{subject}}}`: the domain for which the generated challenge-fulfilling
|
* `{{{subject}}}`: the domain for which the generated challenge-fulfilling
|
||||||
certificate must be used (only available when generating it)
|
certificate must be used (only available when generating it)
|
||||||
* `{{{cert}}}`: the path to the generated certificate: `apache-path/token.crt`
|
* `{{{cert}}}`: the path to the generated certificate: `hooks-path/token.crt`
|
||||||
* `{{{privkey}}}`: the path to the generated private key: `apache-path/token.key`
|
* `{{{privkey}}}`: the path to the generated private key: `hooks-path/token.key`
|
||||||
* `{{{conf}}}`: the path to the generated config file: `apache-path/token.conf`
|
* `{{{conf}}}`: the path to the generated config file: `hooks-path/token.conf`
|
||||||
* `{{{bind}}}`: the value of the `apache-bind` option
|
* `{{{bind}}}`: the value of the `hooks-bind` option
|
||||||
* `{{{port}}}`: the value of the `apache-port` option
|
* `{{{port}}}`: the value of the `hooks-port` option
|
||||||
* `{{{webroot}}}`: the value of the `apache-webroot` option
|
* `{{{webroot}}}`: the value of the `hooks-webroot` option
|
||||||
|
|
||||||
### Interactive (for debugging)
|
### 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
|
sudo chown -R $(whoami) /etc/letsencrypt /var/lib/letsencrypt /var/log/letsencrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
## Command line Options
|
## Command Line Options
|
||||||
|
|
||||||
```
|
```
|
||||||
Usage:
|
Usage:
|
||||||
|
@ -285,33 +288,34 @@ Options:
|
||||||
|
|
||||||
--webroot-path STRING public_html / webroot path.
|
--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)
|
(Default is ~/letsencrypt/apache)
|
||||||
|
|
||||||
--apache-bind [STRING] IP address to use for Apache virtual host. (Default is *)
|
--hooks-server STRING Type of webserver to configure. Sets defaults for all the following --hooks- options.
|
||||||
(This is used in the default template.)
|
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)
|
--hooks-template STRING Template to use for hooks configuration file.
|
||||||
(This is used in the default template.)
|
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)
|
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.
|
--hooks-enable STRING Hook to enable the webserver configuration.
|
||||||
(Default is `ln -s {{{conf}}} /etc/apache2/sites-enabled`)
|
|
||||||
|
|
||||||
--apache-check STRING Command to run to check Apache configuration.
|
--hooks-pre-reload STRING Hook to check the webserver configuration prior to reloading.
|
||||||
(Default is `apache2ctl configtest`)
|
|
||||||
|
|
||||||
--apache-reload STRING Command to run to reload Apache.
|
--hooks-reload STRING Hook to reload the webserver.
|
||||||
(Default is `/etc/init.d/apache2 reload`)
|
|
||||||
|
|
||||||
--apache-disable STRING Command to run to disable the site in Apache.
|
--hooks-disable STRING Hook to disable the webserver configuration.
|
||||||
(Default is `rm /etc/apache2/sites-enabled/{{{token}}}.conf`)
|
|
||||||
|
|
||||||
--debug BOOLEAN show traces and logs
|
--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 ]
|
, 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: [ false, " Obtain certs by placing files in a webroot directory.", 'boolean', false ]
|
||||||
, 'webroot-path': [ false, " public_html / webroot path.", 'string' ]
|
, 'webroot-path': [ false, " public_html / webroot path.", 'string' ]
|
||||||
, apache: [ false, " Obtain certs using Apache virtual hosts.", 'boolean', false ]
|
, hooks: [ false, " Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges.", 'boolean', false ]
|
||||||
, 'apache-path': [ false, " Path in which to store files for Apache virtual hosts.", 'string' ]
|
, 'hooks-path': [ false, " Path in which to store files for hooks.", 'string' ]
|
||||||
, 'apache-bind': [ false, " IP address to use for Apache virtual host.", 'string', "*" ]
|
, 'hooks-server': [ false, " Type of webserver to configure.", 'string' ]
|
||||||
, 'apache-port': [ false, " Port to use for Apache virtual host.", 'int', 443 ]
|
, 'hooks-template': [ false, " Template to use for hooks configuration file.", 'string' ]
|
||||||
, 'apache-webroot': [ false, " Webroot to use for Apache virtual host (e.g. empty dir).", 'string' ]
|
, 'hooks-bind': [ false, " IP address to use in configuration for hooks.", 'string' ]
|
||||||
, 'apache-template': [ false, " Alternative template to use for Apache configuration file.", 'string' ]
|
, 'hooks-port': [ false, " Port to use in configuration for hooks.", 'string' ]
|
||||||
, 'apache-enable': [ false, " Command to run to enable the site in Apache.", 'string' ]
|
, 'hooks-webroot': [ false, " Webroot to use in configuration for hooks (e.g. empty dir).", 'string' ]
|
||||||
, 'apache-check': [ false, " Command to run to check Apache configuration.", 'string' ]
|
, 'hooks-pre-enable': [ false, " Hook to check the webserver configuration prior to enabling.", 'string' ]
|
||||||
, 'apache-reload': [ false, " Command to run to reload Apache.", 'string' ]
|
, 'hooks-enable': [ false, " Hook to enable the webserver configuration.", 'string' ]
|
||||||
, 'apache-disable': [ false, " Command to run to disable the site in Apache.", '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']
|
//, '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 ]
|
, debug: [ false, " show traces and logs", 'boolean', false ]
|
||||||
, 'work-dir': [ false, "(ignored)", 'string', '~/letsencrypt/var/lib/' ]
|
, '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';
|
challengeType = 'dns-01';
|
||||||
args.webrootPath = '';
|
args.webrootPath = '';
|
||||||
args.standalone = USE_DNS;
|
args.standalone = USE_DNS;
|
||||||
} else if (args.tlsSni01Port || args.apache) {
|
} else if (args.tlsSni01Port || args.hooks) {
|
||||||
challengeType = 'tls-sni-01';
|
challengeType = 'tls-sni-01';
|
||||||
args.webrootPath = '';
|
args.webrootPath = '';
|
||||||
} else /*if (args.http01Port)*/ {
|
} else /*if (args.http01Port)*/ {
|
||||||
|
@ -25,17 +25,19 @@ module.exports.run = function (args) {
|
||||||
if (args.manual) {
|
if (args.manual) {
|
||||||
leChallenge = require('le-challenge-manual').create({});
|
leChallenge = require('le-challenge-manual').create({});
|
||||||
}
|
}
|
||||||
else if (args.apache) {
|
else if (args.hooks) {
|
||||||
leChallenge = require('le-challenge-apache').create({
|
leChallenge = require('le-challenge-hooks').create({
|
||||||
apachePath: args.apachePath
|
hooksPath: args.hooksPath
|
||||||
, apacheBind: args.apacheBind
|
, hooksServer: args.hooksServer
|
||||||
, apachePort: args.apachePort
|
, hooksTemplate: args.hooksTemplate
|
||||||
, apacheWebroot: args.apacheWebroot
|
, hooksBind: args.hooksBind
|
||||||
, apacheTemplate: args.apacheTemplate
|
, hooksPort: args.hooksPort
|
||||||
, apacheEnable: args.apacheEnable
|
, hooksWebroot: args.hooksWebroot
|
||||||
, apacheCheck: args.apacheCheck
|
, hooksPreEnable: args.hooksPreEnable
|
||||||
, apacheReload: args.apacheReload
|
, hooksEnable: args.hooksEnable
|
||||||
, apacheDisable: args.apacheDisable
|
, hooksPreReload: args.hooksPreReload
|
||||||
|
, hooksReload: args.hooksReload
|
||||||
|
, hooksDisable: args.hooksDisable
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if (args.webrootPath) {
|
else if (args.webrootPath) {
|
||||||
|
@ -52,9 +54,10 @@ module.exports.run = function (args) {
|
||||||
servers = require('./lib/servers').create(leChallenge);
|
servers = require('./lib/servers').create(leChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var privkeyPath = args.domainKeyPath || ':configDir/live/:hostname/privkey.pem'; //args.privkeyPath
|
||||||
leStore = require('le-store-certbot').create({
|
leStore = require('le-store-certbot').create({
|
||||||
configDir: args.configDir
|
configDir: args.configDir
|
||||||
, privkeyPath: args.domainKeyPath || ':configDir/live/:hostname/privkey.pem' //args.privkeyPath
|
, privkeyPath: privkeyPath
|
||||||
, fullchainPath: args.fullchainPath
|
, fullchainPath: args.fullchainPath
|
||||||
, certPath: args.certPath
|
, certPath: args.certPath
|
||||||
, chainPath: args.chainPath
|
, chainPath: args.chainPath
|
||||||
|
@ -123,14 +126,26 @@ module.exports.run = function (args) {
|
||||||
console.log("\tIssued at " + new Date(certs.issuedAt).toISOString() + "");
|
console.log("\tIssued at " + new Date(certs.issuedAt).toISOString() + "");
|
||||||
console.log("\tValid until " + new Date(certs.expiresAt).toISOString() + "");
|
console.log("\tValid until " + new Date(certs.expiresAt).toISOString() + "");
|
||||||
console.log("");
|
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?
|
// should get back account, path to certs, pems, etc?
|
||||||
console.log('\nCertificates installed at:');
|
console.log('Certificates installed at:');
|
||||||
console.log(Object.keys(args).filter(function (key) {
|
console.log(
|
||||||
return /Path/.test(key);
|
[
|
||||||
}).map(function (key) {
|
args.certPath
|
||||||
return args[key];
|
, args.chainPath
|
||||||
}).join('\n').replace(/:hostname/g, args.domains[0]));
|
, args.fullchainPath
|
||||||
|
].join('\n')
|
||||||
|
.replace(/:configDir/g, args.configDir)
|
||||||
|
.replace(/:hostname/g, args.domains[0])
|
||||||
|
);
|
||||||
|
console.log("");
|
||||||
|
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
|
|
|
@ -36,12 +36,12 @@
|
||||||
"cli": "^0.11.1",
|
"cli": "^0.11.1",
|
||||||
"homedir": "^0.6.0",
|
"homedir": "^0.6.0",
|
||||||
"le-acme-core": "^2.0.5",
|
"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-manual": "^2.0.0",
|
||||||
"le-challenge-sni": "^2.0.0",
|
"le-challenge-sni": "^2.0.0",
|
||||||
"le-challenge-standalone": "^2.0.0",
|
"le-challenge-standalone": "^2.0.0",
|
||||||
"le-store-certbot": "^2.0.2",
|
"le-store-certbot": "^2.0.2",
|
||||||
"letsencrypt": "^2.1.2",
|
"letsencrypt": "^2.1.8",
|
||||||
"localhost.daplie.com-certificates": "^1.2.0",
|
"localhost.daplie.com-certificates": "^1.2.0",
|
||||||
"mkdirp": "^0.5.1"
|
"mkdirp": "^0.5.1"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue