mirror of
				https://git.coolaj86.com/coolaj86/greenlock-cli.js
				synced 2025-11-04 02:52:48 +00:00 
			
		
		
		
	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user