From 8cf13b329a383237ac73a3eff8e7e175a432f14d Mon Sep 17 00:00:00 2001 From: AJ ONeal Date: Sun, 13 May 2018 01:31:44 -0600 Subject: [PATCH] making progress --- README.md | 305 +++++++++++++++++++++++--------------------- bin/greenlock.js | 63 ++++++--- examples/server.sh | 8 ++ examples/webroot.sh | 7 + package.json | 14 +- 5 files changed, 221 insertions(+), 176 deletions(-) create mode 100644 examples/server.sh create mode 100644 examples/webroot.sh diff --git a/README.md b/README.md index a736c87..6b525b9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![Greenlock Logo](https://git.coolaj86.com/coolaj86/greenlock.js/raw/branch/master/logo/greenlock-1063x250.png "Greenlock Logo") -# Greenlock™ for Web Servers +# Greenlock™ Certificate Manager for Web Servers A server-friendly commandline tool for Free SSL, Free Wildcard SSL, and Fully Automated HTTPS certificates issued by Let's Encrypt v2 via ACME @@ -10,6 +10,59 @@ Greenlock is also available [for node.js](https://git.coolaj86.com/coolaj86/greenlock-express.js), and [for API integrations](https://git.coolaj86.com/coolaj86/greenlock.js) +Why use Greenlock? Two Reasons: +=============================== + +One +--- + +You want to be able to run a command like this: + +```bash +sudo greenlock --domains example.com --config /etc/greenlock/greenlock.yml +``` + +And then get awesome results like this: + +``` +/etc/ssl/acme +├── accounts +│   └── acme-staging-v02.api.letsencrypt.org/directory +│   └── c07a31a70c691d64f6b4d31f51a6dd9c +│  ├── meta.json +│  ├── private_key.json +│  └── regr.json +└── live +    └── example.com <-- Free SSL like magic! Wow! +    ├── bundle.pem +    ├── cert.pem +    ├── chain.pem +    ├── fullchain.pem +    └── privkey.pem +``` + +That you use with your existing webserver - Apache, Nginx, HAProxy, node.js, etc + +And install to renew so that you never worry about ssl again. + +Two +--- + +You want to be able to run a command like this: + +```bash +sudo greenlock --install systemd --config /etc/greenlock.yml --webroot '/srv/www/:hostname' +``` + +To immediately secure and publish any and all sites you have in a web root like this: + +``` +/srv/www/ +├── coolsite.rocks +├── example.com +└── whatever.app +``` + Features ======== @@ -28,54 +81,15 @@ Features - [x] HTTP Challenge Plugins - AWS S3, Azure, Consul, etcd - [x] DNS Challenge Plugins - AWS Route53, CloudFlare, Digital Ocean - [x] Account & Certificate Storage Plugins - AWS S3, Redis - -Demo -==== - -Run as a webserver: - -```bash -sudo greenlock --daemon \ - --email jon@example.com \ - --agree-tos \ - --root /srv/www/example.com \ - --domains example.com,www.example.com -``` - -Fetch certificates for Apache, Nginx, or HAProxy: - -```bash -greenlock --email jon@example.com \ - --agree-tos \ - --domains example.com,www.example.com \ - --webroot-path /srv/www/example.com \ - --privkey-path /etc/ssl/privkey.pem \ - --fullchain-path /etc/ssl/fullchain.pem \ - --bundle-path /etc/ssl/bundle.pem -``` - -Robust configurations for Greenlock as a system service - -```bash -sudo greenlock --install systemd --config /etc/greenlock/greenlock.yml -``` - -See explanations below in the **Usage** section. + - [x] Built-in WebServer Install ======= -Windows -------- - -1. Install node.js -2. Open `Node.js cmd.exe` -2. Run the command `npm install -g greenlock-cli` - Mac --- -Open Terminal +Open Terminal and run this install script: ```bash curl -fsS https://get.greenlock.app/ | bash @@ -84,10 +98,111 @@ curl -fsS https://get.greenlock.app/ | bash Linux ----- +Open Terminal and run this install script: + ```bash curl -fsS https://get.greenlock.app/ | bash ``` +Windows & Node.js +----------------- + +1. Install [node.js](https://nodejs.org) +2. Open _Node.js_ +2. Run the command `npm install -g greenlock-cli` + +Important: How to Not Get Blocked +=================== + +PLEASE READ ALL THREE SENTENCES: + + * These examples use the PRODUCTION ENVIRONMENT (where you can be blocked) + * If an example DOESN'T WORK on the first try, STOP! + * UNCOMMENT the `--staging` flag and see the TROUBLESHOOTING SECTION + +Quick Examples +============== + +The most basic options are exposed as commandline flags, +just so that we can do little domes like this. + +The config file is explained after the troubleshooting section. + +### The Greenlock HTTPS WebServer + +Easy to run on your server, nothing else required: + +```bash +sudo greenlock --webserver \ + --agree-tos --email jon@example.com \ + --domains example.com,www.example.com \ + --webroot /srv/www/example.com \ + --config-dir ~/acme/etc #--staging +``` + +### Add SSL to an Existing WebServer + +For all the Apache, Nginx, and HAProxy fans out there: + +(use your existing webroot) + +```bash +sudo greenlock --agree-tos --email jon@example.com \ + --domains example.com,www.example.com \ + --webroot /srv/www/example.com \ + --privkey-path /etc/ssl/example.com/privkey.pem \ + --fullchain-path /etc/ssl/example.com/fullchain.pem \ + --bundle-path /etc/ssl/example.com/bundle.pem \ + --config-dir /etc/ssl/acme #--staging +``` + +### Get SSL Certificates Interactively + +Run this manual process on your laptop and copy the certificates +to you server afterwards: + +```bash +greenlock --agree-tos --email jon@example.com \ + --domains example.com,www.example.com \ + --privkey-path /etc/ssl/example.com/privkey.pem \ + --fullchain-path /etc/ssl/example.com/fullchain.pem \ + --bundle-path /etc/ssl/example.com/bundle.pem \ + --manual \ + --config-dir /etc/ssl/acme #--staging +``` + +### Standalone SSL Certificate Retrieval + +Run this on a server standalone just to retrieve +certificates: + +```bash +sudo greenlock --agree-tos --email jon@example.com \ + --domains example.com,www.example.com \ + --privkey-path /etc/ssl/example.com/privkey.pem \ + --fullchain-path /etc/ssl/example.com/fullchain.pem \ + --bundle-path /etc/ssl/example.com/bundle.pem \ + --standalone \ + --config-dir ~/etc/ssl/acme #--staging +``` + +Troubleshooting +=============== + +Watch the [Troubleshooting Screencast](https://youtu.be/e8vaR4CEZ5s?t=397) + +**Note**: Replace `whatever.com` with your domain, use your real email, etc. + +0. Use the `--staging` flag while troubleshooting +1. Do you have a valid A record for `whatever.com`? +2. When you `ping whatever.com` do you see that same address? +3. Can you confirm that's your server's address with `ifconfig` or `ipconfig`? +4. Do you have write access to all of the directories you've specified? + +**Important**: Don't forget to delete the directory specified in `--config-dir` +when you get things figured out and remove `--staging`. + + Usage ===== @@ -138,7 +253,7 @@ This option is great for testing, but since it requires the use of the same ports that your webserver needs, it isn't a good choice for production. -### WebRoot (production option 1) +### WebRoot You can specify the path to where you keep your `index.html` with `webroot`, as long as your server is serving plain HTTP on port 80. @@ -168,71 +283,6 @@ 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. -### 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 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 greenlock certonly \ - --agree-tos --email john.doe@example.com \ - --hooks --hooks-server apache2-debian \ - --config-dir /etc/acme \ - --domains example.com,www.example.com \ - --server https://acme-staging-v02.api.letsencrypt.org/directory - --acme-version draft-11 -``` - -Three files are then generated: - -* a configuration fragment: `some-long-string.conf` -* a challenge-fulfilling certificate: `the-same-long-string.crt` -* a private key: `the-same-long-string.key` - -A hook is then run to enable the fragment, e.g. by linking it (it should not be -moved) into a `conf.d` directory (for Apache on Debian, `sites-enabled`). A -second hook is then run to check the configuration is valid, to avoid -accidental downtime, and then another to signal to the server to reload the -configuration. The server will now serve the generated certificate on a special -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. - -You can then find your brand new certs in: - -``` -ls /etc/letsencrypt/live/ -``` - -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: `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) The token (for all challenge types) and keyAuthorization (only for https-01) @@ -310,11 +360,6 @@ Options: --renew-within [NUMBER] Renew certificates this many days before expiry. (default: 7) - --duplicate BOOLEAN Allow getting a certificate that duplicates an existing one/is - an early renewal. - - --rsa-key-size [NUMBER] Size (in bits) of the RSA key. (Default is 2048) - --cert-path STRING Path to where new cert.pem is saved (Default is :conf/live/:hostname/cert.pem) @@ -326,13 +371,8 @@ Options: --domain-key-path STRING Path to privkey.pem to use for domain (default: generate new) - --account-key-path STRING Path to privkey.pem to use for account (default: generate new) - --config-dir STRING Configuration directory. (Default is ~/letsencrypt/etc/) - --tls-sni-01-port NUMBER Use TLS-SNI-01 challenge type with this port. - (must be 443 with most production servers) (Boulder allows 5001 in testing mode) - --http-01-port [NUMBER] Use HTTP-01 challenge type with this port, used for SimpleHttp challenge. (Default is 80) (must be 80 with most production servers) @@ -347,35 +387,6 @@ Options: --webroot-path STRING public_html / webroot path. - --hooks BOOLEAN Obtain certs with hooks that configure a webserver to meet TLS-SNI-01 challenges. - - --hooks-path STRING Path in which to store files for hooks. - (Default is ~/letsencrypt/apache) - - --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.) - - --hooks-template STRING Template to use for hooks configuration file. - Either --hooks-server or --hooks-template must be given. - - --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) - - --hooks-pre-enable STRING Hook to check the webserver configuration prior to enabling. - - --hooks-enable STRING Hook to enable the webserver configuration. - - --hooks-pre-reload STRING Hook to check the webserver configuration prior to reloading. - - --hooks-reload STRING Hook to reload the webserver. - - --hooks-disable STRING Hook to disable the webserver configuration. - --debug BOOLEAN show traces and logs -h, --help Display help and usage details diff --git a/bin/greenlock.js b/bin/greenlock.js index 8de5d3b..bae7432 100755 --- a/bin/greenlock.js +++ b/bin/greenlock.js @@ -6,52 +6,75 @@ var mkdirp = require('mkdirp'); cli.parse({ 'acme-version': - [ false, " v01 (Let's Encrypt v01) or draft-11 (Let's Encrypt v02) (default: draft-11)", 'string', 'draft-11' ] + [ false, " v01 (Let's Encrypt v01) or draft-11 (Let's Encrypt v02) (default: draft-11)", 'string' + , 'draft-11' ] , 'acme-url': - [ false, " ACME API Directory URL (default: https://acme-v02.api.letsencrypt.org/directory", 'string', '' ] + [ false, " ACME API Directory URL (default: https://acme-v02.api.letsencrypt.org/directory", 'string' + , 'https://acme-staging-v02.api.letsencrypt.org/directory' ] + +, 'aol-keyword-www': + [ false, " Travel back in time to 1995 where we redirect bare domains as to have a triple-w prefix", 'string' + , false ] , config: [ 'c', " Path to configuration file --config /etc/greenlock/greenlock.yml (default: '')", 'string' ] , serve: - [ false, " Run as webserver (default: false)", 'boolean', false ] + [ false, " Run as webserver (default: false)", 'boolean' + , false ] , email: - [ false, " Email used for registration and recovery contact (default: '')", 'email', '' ] + [ false, " Email used for registration and recovery contact (default: '')", 'email' ] , analytics: - [ false, " Share analytics with greenlock (default: false)", 'boolean', false ] + [ false, " Share analytics with greenlock (default: false)", 'boolean' + , false ] , community: - [ false, " Join the greenlock community to get important updates (default: false)", 'boolean', false ] + [ false, " Join the greenlock community to get important updates (default: false)", 'boolean' + , false ] , 'agree-tos': - [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean', false ] + [ false, " Agree to the Let's Encrypt Subscriber Agreement", 'boolean' + , false ] , domains: [ false, " Comma-separated list of domains to secure (default: [])", 'string' ] , 'config-dir': - [ false, " Configuration directory.", 'string', '~/acme/etc/' ] + [ false, " Configuration directory.", 'string' + , '~/acme/etc/' ] , 'cert-path': - [ false, " Path where new cert.pem is saved", 'string',':configDir/live/:hostname/cert.pem' ] + [ false, " Path where new cert.pem is saved", 'string' + , ':configDir/live/:hostname/cert.pem' ] , 'fullchain-path': - [ false, " Path where new fullchain.pem (cert + chain) is saved", 'string', ':configDir/live/:hostname/fullchain.pem' ] + [ false, " Path where new fullchain.pem (cert + chain) is saved", 'string' + , ':configDir/live/:hostname/fullchain.pem' ] , 'chain-path': - [ false, " Path where new chain.pem is saved", 'string', ':configDir/live/:hostname/chain.pem' ] + [ false, " Path where new chain.pem is saved", 'string' + , ':configDir/live/:hostname/chain.pem' ] , 'bundle-path': - [ false, " Path where new bundle.pem (fullchain + privkey) is saved", 'string', ':configDir/live/:hostname/bundle.pem' ] + [ false, " Path where new bundle.pem (fullchain + privkey) is saved", 'string' + , ':configDir/live/:hostname/bundle.pem' ] , 'privkey-path': - [ false, " Path where (new or existing) domain privkey.pem is saved", 'string', ':configDir/live/:hostname/privkey.pem' ] -, 'root': - [ false, " public_html / webroot path /srv/www/:hostname", 'string' ] + [ false, " Path where (new or existing) domain privkey.pem is saved", 'string' + , ':configDir/live/:hostname/privkey.pem' ] +, 'webroot': + [ false, " public_html / webroot path such as /srv/www/:hostname", 'string' ] , 'renew-within': - [ false, " Renew certificates this many days before expiry", 'int', 11 ] + [ false, " Renew certificates this many days before expiry", 'int' + , 11 ] +, staging: + [ false, " Use Let's Encrypt v02 staging API", 'boolean' + , false ] , standalone: - [ false, " Obtain certs using a \"standalone\" webserver.", 'boolean', false ] + [ false, " Obtain certs using a \"standalone\" webserver", '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 ] + [ 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 ] , debug: - [ false, " show traces and logs", 'boolean', false ] + [ false, " show traces and logs", 'boolean' + , false ] }); // ignore certonly and extraneous arguments cli.main(function(_, options) { console.log(''); var args = {}; - var homedir = require('homedir')(); + var homedir = require('os').homedir(); Object.keys(options).forEach(function (key) { var val = options[key]; diff --git a/examples/server.sh b/examples/server.sh new file mode 100644 index 0000000..48f8d81 --- /dev/null +++ b/examples/server.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +greenlock \ + --agree-tos --email 'john.doe@gmail.com' \ + --serve + --root /root/www/example.com \ + --domains example.com,www.example.com \ + --config-dir ~/acme.test/etc diff --git a/examples/webroot.sh b/examples/webroot.sh new file mode 100644 index 0000000..550e1cc --- /dev/null +++ b/examples/webroot.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +greenlock \ + --agree-tos --email 'john.doe@gmail.com' \ + --root /root/www/example.com \ + --domains example.com,www.example.com \ + --config-dir ~/acme.test/etc diff --git a/package.json b/package.json index 866fdc6..6dd086d 100644 --- a/package.json +++ b/package.json @@ -34,15 +34,11 @@ }, "homepage": "https://git.coolaj86.com/coolaj86/greenlock-cli.js", "dependencies": { - "cli": "^0.11.1", - "greenlock": "^2.1.16", - "homedir": "^0.6.0", - "le-acme-core": "^2.0.5", - "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", + "cli": "^1.0.1", + "greenlock": "^2.2.11", + "le-challenge-manual": "^2.1.0", + "le-challenge-standalone": "^2.1.0", + "le-store-certbot": "^2.1.0", "mkdirp": "^0.5.1" } }