mirror of
				https://github.com/therootcompany/greenlock-express.js.git
				synced 2024-11-16 17:28:59 +00:00 
			
		
		
		
	v3.0.0: first draft of docs
This commit is contained in:
		
							parent
							
								
									31ba1186be
								
							
						
					
					
						commit
						00e9d96f8b
					
				
							
								
								
									
										610
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										610
									
								
								README.md
									
									
									
									
									
								
							| @ -1,466 +1,260 @@ | |||||||
| # Greenlock v3 on its way (Nov 1st, 2019) | # [Greenlock Express](https://git.rootprojects.org/root/greenlock-express.js) is Let's Encrypt for Node | ||||||
| 
 |  | ||||||
| Greenlock v3 is in private beta (for backers) and will be available publicly by Nov 1st. |  | ||||||
| 
 |  | ||||||
| You can keep an eye for updates on the [campaign page](https://indiegogo.com/at/greenlock) and, |  | ||||||
| if this has been a useful project that's saved you time, [please contribute](https://paypal.me/rootprojects/99). |  | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
| 
 | 
 | ||||||
|  | | Built by [Root](https://therootcompany.com) for [Hub](https://rootprojects.org/hub/) | ||||||
| 
 | 
 | ||||||
| <table> | Free SSL, Automated HTTPS / HTTP2, served with Node via Express, Koa, hapi, etc. | ||||||
|   <tr> |  | ||||||
|     <td><a href="https://medium.com/@bohou/secure-your-nodejs-server-with-letsencrypt-for-free-f8925742faa9" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/ibm-301x112.png"></a></td> |  | ||||||
|     <td><a href="https://github.com/mozilla-iot/le-store-certbot/issues/4" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/mozilla-iot-301x112.png"></a></td> |  | ||||||
|     <td><a href="https://github.com/digitalbazaar/bedrock-letsencrypt" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/digital-bazaar-301x112.png"></a></td> |  | ||||||
|   </tr> |  | ||||||
| </table> |  | ||||||
| <table> |  | ||||||
|   <tr> |  | ||||||
|     <td><a href="https://github.com/beakerbrowser/homebase" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/beaker-browser-301x112.png"></a></td> |  | ||||||
|     <td><a href="https://telebit.cloud" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/telebit-301x112.png"></a></td> |  | ||||||
|     <td><a href="https://rootprojects.org" target="_blank"><img src="https://git.rootprojects.org/root/greenlock.js/raw/branch/master/logo/ppl-301x112.png"></a></td> |  | ||||||
|   </tr> |  | ||||||
| </table> |  | ||||||
| 
 | 
 | ||||||
| # [Greenlock](https://git.rootprojects.org/root/greenlock-express.js)™ for Express.js | a [Root](https://rootprojects.org) project | ```js | ||||||
|  | require("greenlock-express") | ||||||
|  | 	.init(getConfig) | ||||||
|  | 	.serve(worker); | ||||||
| 
 | 
 | ||||||
| <small>formerly letsencrypt-express</small> | function getConfig() { | ||||||
|  | 	return { | ||||||
|  | 		package: require("./package.json") | ||||||
|  | 	}; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| Free SSL, Free Wildcard SSL, and Fully Automated HTTPS made dead simple<br> | function worker(server) { | ||||||
| <small>certificates issued by Let's Encrypt v2 via [ACME](https://git.rootprojects.org/root/acme-v2.js)</small> | 	server.serveApp(function(req, res) { | ||||||
|  | 		// Works with any Node app (Express, etc) | ||||||
|  | 		res.end("Hello, Encrypted World!"); | ||||||
|  | 	}); | ||||||
|  | } | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
|  | # Let's Encrypt for... | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| <a href="https://twitter.com/intent/follow?screen_name=GreenlockHTTPS"><img src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Follow%20@GreenlockHTTPS" title="Follow @GreenlockHTTPS on Twitter" alt="Twitter Badge"></a> |  | ||||||
| 
 | 
 | ||||||
| [Greenlock™](https://git.rootprojects.org/root/greenlock.js) is for | - IoT | ||||||
| [Web Servers](https://git.rootprojects.org/root/greenlock-cli.js), | - Enterprise On-Prem | ||||||
| [Web Browsers](https://greenlock.domains), | - Local Development | ||||||
| and **node.js middleware systems**. | - Home Servers | ||||||
|  | - Quitting Heroku | ||||||
| 
 | 
 | ||||||
| # Features | # Features | ||||||
| 
 | 
 | ||||||
| - [x] Automatic HTTPS | - [x] Let's Encrypt v2 (November 2019) | ||||||
|  |   - [x] ACME Protocol (RFC 8555) | ||||||
|  |   - [x] HTTP Validation (HTTP-01) | ||||||
|  |   - [x] DNS Validation (DNS-01) | ||||||
|  |   - [ ] ALPN Validation (TLS-ALPN-01) | ||||||
|  |     - Need ALPN validation? [contact us](mailto:greenlock-support@therootcompany.com) | ||||||
|  | - [x] Automated HTTPS | ||||||
|  |   - [x] Fully Automatic Renewals every 45 days | ||||||
|   - [x] Free SSL |   - [x] Free SSL | ||||||
|   - [x] Free Wildcard SSL |   - [x] **Wildcard** SSL | ||||||
|   - [x] Multiple domain support (up to 100 altnames per SAN) |   - [x] **Localhost** certificates | ||||||
|   - [x] Dynamic Virtual Hosting (vhost) |   - [x] HTTPS-enabled Secure **WebSockets** (`wss://`) | ||||||
|   - [x] Automatical renewal (10 to 14 days before expiration) | - [x] Fully customizable | ||||||
| - [x] Great ACME support |   - [x] **Reasonable defaults** | ||||||
|   - [x] ACME draft 11 |   - [x] Domain Management | ||||||
|   - [x] Let's Encrypt v2 |   - [x] Key and Certificate Management | ||||||
|   - [x] Let's Encrypt v1 |   - [x] ACME Challenge Plugins | ||||||
| - [x] Full node.js support |  | ||||||
|   - [x] node v6+ |  | ||||||
|   - [x] core https module |  | ||||||
|   - [x] Express.js |  | ||||||
|   - [x] [Koa](https://git.rootprojects.org/root/greenlock-koa.js) |  | ||||||
|   - [x] [hapi](https://git.rootprojects.org/root/greenlock-hapi.js) |  | ||||||
| - [x] Extensible Plugin Support |  | ||||||
|   - [x] AWS (S3, Route53) |  | ||||||
|   - [x] Azure |  | ||||||
|   - [x] CloudFlare |  | ||||||
|   - [x] Consul |  | ||||||
|   - [x] Digital Ocean |  | ||||||
|   - [x] etcd |  | ||||||
|   - [x] Redis |  | ||||||
| 
 | 
 | ||||||
| # Install | # Plenty of Examples | ||||||
|  | 
 | ||||||
|  | - [greenlock-express.js/examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) | ||||||
|  |   - [Express](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/express.js) | ||||||
|  |   - [Node's **http2**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2.js) | ||||||
|  |   - [Node's https](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/https.js) | ||||||
|  |   - [**WebSockets**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets.js) | ||||||
|  |   - [Socket.IO](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket-io.js) | ||||||
|  |   - [Cluster](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket-io.js) | ||||||
|  |   - [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/README.md) | ||||||
|  |   - [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/README.md) | ||||||
|  |   - [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/README.md) | ||||||
|  | 
 | ||||||
|  | # Easy to Customize | ||||||
|  | 
 | ||||||
|  | <!-- greenlock-manager-test => greenlock-manager-custom --> | ||||||
|  | 
 | ||||||
|  | - [greenlock.js/examples/](https://git.rootprojects.org/root/greenlock.js/src/branch/master/examples) | ||||||
|  |   - [Custom Domain Management](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/custom-manager/README.md) | ||||||
|  |   - [Custom Key & Cert Storage](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/custom-store/README.md) | ||||||
|  |   - [Custom ACME Challenges](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/custom-acme-challenges/README.md) | ||||||
|  | 
 | ||||||
|  | # QuickStart Guide | ||||||
|  | 
 | ||||||
|  | Easy as 1, 2, 3... 4 | ||||||
|  | 
 | ||||||
|  | ## 1. Create a node project | ||||||
|  | 
 | ||||||
|  | Create an empty node project. | ||||||
|  | 
 | ||||||
|  | Be sure to fill out the package name, version, and an author email. | ||||||
| 
 | 
 | ||||||
| ```bash | ```bash | ||||||
| npm install --save greenlock-express@2.x | mkdir ~/my-project | ||||||
|  | pushd ~/my-project | ||||||
|  | npm init | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| # QuickStart | ## 2. Create an http app (i.e. express) | ||||||
| 
 | 
 | ||||||
| <!-- TODO better quickstart (fewer options) --> | This example is shown with Express, but any node app will doGreenlock | ||||||
|  | works with everything. | ||||||
|  | (or any node-style http app) | ||||||
| 
 | 
 | ||||||
| ### Screencast | `my-express-app.js`: | ||||||
| 
 |  | ||||||
| Watch the QuickStart demonstration: [https://youtu.be/e8vaR4CEZ5s](https://youtu.be/e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk) |  | ||||||
| 
 |  | ||||||
| <a href="https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk"><img src="https://i.imgur.com/Y8ix6Ts.png" title="QuickStart Video" alt="YouTube Video Preview" /></a> |  | ||||||
| 
 |  | ||||||
| - [0:00](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=0) - Intro |  | ||||||
| - [2:22](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk#t=142) - Demonstrating QuickStart Example |  | ||||||
| - [6:37](https://www.youtube.com/watch?v=e8vaR4CEZ5s&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk?t=397) - Troubleshooting / Gotchas |  | ||||||
| 
 |  | ||||||
| #### Beyond the QuickStart (Part 2) |  | ||||||
| 
 |  | ||||||
| - [1:00](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=60) - Bringing Greenlock into an Existing Express Project |  | ||||||
| - [2:26](https://www.youtube.com/watch?v=bTEn93gxY50&index=2&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk&t=146) - The `approveDomains` callback |  | ||||||
| 
 |  | ||||||
| #### Security Concerns (Part 3) |  | ||||||
| 
 |  | ||||||
| - [0:00](https://www.youtube.com/watch?v=aZgVqPzoZTY&index=3&list=PLZaEVINf2Bq_lrS-OOzTUJB4q3HxarlXk) - Potential Attacks, and Mitigation |  | ||||||
| 
 |  | ||||||
| ### Working Example Code |  | ||||||
| 
 |  | ||||||
| Here's a completely working example that will get you started. |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| git clone https://git.rootprojects.org/root/greenlock-express.js.git |  | ||||||
| pushd greenlock-express.js |  | ||||||
|   npm install |  | ||||||
| popd |  | ||||||
| 
 |  | ||||||
| # edit 'email' and 'approveDomains' in |  | ||||||
| # greenlock-express.js/examples/simple.js |  | ||||||
| 
 |  | ||||||
| node greenlock-express.js/examples/simple.js |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| All you have to do is start the webserver and then visit it at its domain name. |  | ||||||
| 
 |  | ||||||
| `server.js`: |  | ||||||
| 
 |  | ||||||
| ```javascript |  | ||||||
| "use strict"; |  | ||||||
| 
 |  | ||||||
| require("greenlock-express") |  | ||||||
| 	.create({ |  | ||||||
| 		email: "john.doe@example.com", // The email address of the ACME user / hosting provider |  | ||||||
| 		agreeTos: true, // You must accept the ToS as the host which handles the certs |  | ||||||
| 		configDir: "~/.config/acme/", // Writable directory where certs will be saved |  | ||||||
| 		communityMember: true, // Join the community to get notified of important updates |  | ||||||
| 		telemetry: true, // Contribute telemetry data to the project |  | ||||||
| 
 |  | ||||||
| 		// Using your express app: |  | ||||||
| 		// simply export it as-is, then include it here |  | ||||||
| 		app: require("./app.js") |  | ||||||
| 
 |  | ||||||
| 		//, debug: true |  | ||||||
| 	}) |  | ||||||
| 	.listen(80, 443); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| `app.js`: |  | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| "use strict"; | "use strict"; | ||||||
| 
 | 
 | ||||||
|  | // A plain, node-style app | ||||||
|  | 
 | ||||||
|  | function myPlainNodeHttpApp(req, res) { | ||||||
|  | 	res.end("Hello, Encrypted World!"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Wrap that plain app in express, | ||||||
|  | // because that's what you're used to | ||||||
|  | 
 | ||||||
| var express = require("express"); | var express = require("express"); | ||||||
| var app = express(); | var app = express(); | ||||||
|  | app.get("/", myPlainNodeHttpApp); | ||||||
| 
 | 
 | ||||||
| app.use("/", function(req, res) { | // export the app normally | ||||||
| 	res.setHeader("Content-Type", "text/html; charset=utf-8"); | // do not .listen() | ||||||
| 	res.end("Hello, World!\n\n💚 🔒.js"); |  | ||||||
| }); |  | ||||||
| 
 | 
 | ||||||
| // Don't do this: |  | ||||||
| // app.listen(3000) |  | ||||||
| 
 |  | ||||||
| // Do this instead: |  | ||||||
| module.exports = app; | module.exports = app; | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### `communityMember` | ## 3. Serve with Greenlock Express | ||||||
| 
 | 
 | ||||||
| If you're the kind of person that likes the kinds of stuff that I do, | Greenlock Express is designed with these goals in mind: | ||||||
| well, I want to do more of it and I'd like to get you involved. |  | ||||||
| 
 | 
 | ||||||
| As expected, by default we keep your email private and only use it for | - Simplicity and ease-of-use | ||||||
| transactional messaging, urgent security or API updates | - Performance and scalability | ||||||
| (such as the mandatory upgrade to Let's Encrypt v2), and ACME account registration. | - Configurability and control | ||||||
| 
 | 
 | ||||||
| However, when you set the `communityMember` option to `true` we'll also | You can start with **near-zero configuration** and | ||||||
| inform you when there are meaningful and relavant feature updates (no bugfix noise), | slowly add options for greater performance and customization | ||||||
| and give you early access to similar projects. | later, if you need them. | ||||||
| 
 | 
 | ||||||
| You can see our full privacy policy at <https://greenlock.domains/legal/#privacy>. | `server.js`: | ||||||
| 
 | 
 | ||||||
| ### What if the example didn't work? | ```bash | ||||||
|  | require("greenlock-express") | ||||||
|  | 	.init(getConfig) | ||||||
|  | 	.serve(worker); | ||||||
| 
 | 
 | ||||||
| Double check the following: | function getConfig() { | ||||||
|  | 	return { | ||||||
|  | 		// uses name and version as part of the ACME client user-agent | ||||||
|  |     // uses author as the contact for support notices | ||||||
|  | 		package: require("./package.json") | ||||||
|  | 	}; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| - **Public Facing IP** for `http-01` challenges | function worker(server) { | ||||||
|   - Are you running this _as_ a public-facing webserver (good)? or localhost (bad)? | 	// Works with any Node app (Express, etc) | ||||||
|   - Does `ifconfig` show a public address (good)? or a private one - 10.x, 192.168.x, etc (bad)? |   var app = require('my-express-app.js'); | ||||||
|   - If you're on a non-public server, are you using the `dns-01` challenge? | 	server.serveApp(app); | ||||||
| - **correct ACME version** |  | ||||||
|   - Let's Encrypt **v2** (ACME v2) must use `version: 'draft-11'` |  | ||||||
|   - Let's Encrypt v1 must use `version: 'v01'` |  | ||||||
| - **valid email** |  | ||||||
|   - You MUST set `email` to a **valid address** |  | ||||||
|   - MX records must validate (`dig MX example.com` for `'john@example.com'`) |  | ||||||
| - **valid DNS records** |  | ||||||
|   - Must have public DNS records (test with `dig +trace A example.com; dig +trace www.example.com` for `[ 'example.com', 'www.example.com' ]`) |  | ||||||
| - **write access** |  | ||||||
|   - You MUST set `configDir` to a writeable location (test with `touch ~/acme/etc/tmp.tmp`) |  | ||||||
| - **port binding privileges** |  | ||||||
|   - You MUST be able to bind to ports 80 and 443 |  | ||||||
|   - You can do this via `sudo` or [`setcap`](https://gist.github.com/firstdoit/6389682) |  | ||||||
| - **API limits** |  | ||||||
|   - You MUST NOT exceed the API [**usage limits**](https://letsencrypt.org/docs/staging-environment/) per domain, certificate, IP address, etc |  | ||||||
| - **Red Lock, Untrusted** |  | ||||||
|   - You MUST use the **production** server url, not staging |  | ||||||
|   - The API URL should not have 'acme-staging-v02', but should have 'acme-v02' |  | ||||||
|   - Delete the `configDir` used for getting certificates in staging |  | ||||||
| 
 |  | ||||||
| ### Production vs Staging |  | ||||||
| 
 |  | ||||||
| If at first you don't succeed, stop and switch to staging. |  | ||||||
| 
 |  | ||||||
| There are a number of common problems related to system configuration - |  | ||||||
| firewalls, ports, permissions, etc - that you are likely to run up against |  | ||||||
| when using greenlock for your first time. |  | ||||||
| 
 |  | ||||||
| I've put a "dry run" in place with built-in diagnostics, so hopefully |  | ||||||
| you get everything right on your first or second try. |  | ||||||
| 
 |  | ||||||
| However, in order to avoid being blocked by hitting the bad request rate limits |  | ||||||
| you should switch to using the `staging` server for any testing or debugging. |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| https://acme-staging-v02.api.letsencrypt.org/directory |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| ## Working Examples |  | ||||||
| 
 |  | ||||||
| |        Example        |                                                                                                                                        Location + Description                                                                                                                                         | |  | ||||||
| | :-------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | |  | ||||||
| |    **QuickStart**     |                                         [examples/quickstart.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/quickstart.js) uses the fewest options and accepts all default settings. It's guaranteed to work for you.                                          | |  | ||||||
| |      Production       | [examples/production.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/production.js) shows how to require an express app (or other middleware system), expand the `approveDomains` callback, provides an example database shim, and exposes the server instance. | |  | ||||||
| | Virtual Hosting  |                                            [examples/vhost.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/vhost.js) shows how to dynamically secure and serve domains based on their existance on the file system.                                             | |  | ||||||
| | Wildcard Domains |                                                        [examples/wildcard.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcard.js) shows how to use the `acme-dns-01-cli` and wildcard cetificates.                                                         | |  | ||||||
| |   HTTPS (raw)    |                                     [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server using the node's built-in `http` and `https` modules.                                      | |  | ||||||
| |   HTTP2 (spdy)   |             Presently spdy is incompatible with node v11, but [examples/spdy.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/spdy.js) demonstrates how to manually configure a node web server with spdy-compatible versions of node and Greenlock.             | |  | ||||||
| |   HTTP2 (node)   |                             [examples/http2.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/http2.js) uses node's new HTTP2 module, which is NOT compatible with the existing middleware systems (and is not "stable" as of v10.0).                             | |  | ||||||
| | WebSockets (ws)  |                                                     [examples/websockets.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/websockets.js) demonstrates how to use Greenlock express with a websocket server.                                                      | |  | ||||||
| |       socket.io       |                         [examples/socket.io.js](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/socket.io.js) demonstrates how to use Greenlock express with socket.io (even though `ws` is far simpler, faster, and better and every way).                         | |  | ||||||
| |           -           |                                                                    Build Your Own <br> Be sure to tell me ([@solderjs](https://twitter.com/@solderjs)) / us ([@GreenlockHTTPS](https://twitter.com/@GreenlockHTTPS)) about it. :)                                                                     | |  | ||||||
| |    Full List     |                                                                                        Check out the [examples/](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples) directory                                                                                         | |  | ||||||
| 
 |  | ||||||
| # Plugins |  | ||||||
| 
 |  | ||||||
| Plugins developed by `root` are officially maintained, written in Vanilla JS, and typically have 0 dependencies. |  | ||||||
| 
 |  | ||||||
| **IMPORTANT**: |  | ||||||
| Community plugins may or may not be maintained and working. |  | ||||||
| Please try with the defaults before switching to community plugins. |  | ||||||
| 
 |  | ||||||
| ## HTTP-01 Challenges |  | ||||||
| 
 |  | ||||||
| Plugins for ACME / Let's Encrypt HTTP-01 Challenges. |  | ||||||
| 
 |  | ||||||
| |                  |                                                                              Plugin                                                                               | |  | ||||||
| | :--------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------: | |  | ||||||
| | **Default (fs)** |                                         [root/acme-http-01-fs](https://git.rootprojects.org/root/acme-http-01-webroot.js)                                         | |  | ||||||
| | **Manual (cli)** |                                          [root/acme-http-01-cli](https://git.rootprojects.org/root/acme-http-01-cli.js)                                           | |  | ||||||
| |    standalone    |                                   [root/acme-http-01-standalone](https://git.rootprojects.org/root/acme-http-01-standalone.js)                                    | |  | ||||||
| |      AWS S3      |                                           [root/acme-http-01-s3](https://git.rootprojects.org/root/acme-http-01-s3.js)                                            | |  | ||||||
| |      Azure       |                               [kolarcz/node-le-challenge-azure-storage](https://github.com/kolarcz/node-le-challenge-azure-storage)                               | |  | ||||||
| |        -         |                                  Build Your Own <br> [acme-http-01-test](https://git.rootprojects.org/root/acme-http-01-test.js)                                  | |  | ||||||
| |    Full List     | Search [acme-http-01-](https://www.npmjs.com/search?q=acme-http-01-) on npm (or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) for older versions) | |  | ||||||
| 
 |  | ||||||
| ## DNS-01 Challenges |  | ||||||
| 
 |  | ||||||
| Plugins for ACME / Let's Encrypt DNS-01 Challenges. |  | ||||||
| 
 |  | ||||||
| |                  |                                                                   Plugin                                                                   | |  | ||||||
| | :--------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | |  | ||||||
| | **Manual (cli)** |                                [root/acme-dns-01-cli](https://git.rootprojects.org/root/acme-dns-01-cli.js)                                | |  | ||||||
| |    Cloudflare    |                          [nodecraft/acme-dns-01-cloudflare](https://github.com/nodecraft/acme-dns-01-cloudflare)                           | |  | ||||||
| |     DNSimple     |                           [root/acme-dns-01-dnsimple](https://git.rootprojects.org/root/acme-dns-01-dnsimple.js)                           | |  | ||||||
| |  Digital Ocean   |                       [root/acme-dns-01-digitalocean](https://git.rootprojects.org/root/acme-dns-01-digitalocean.js)                       | |  | ||||||
| |     Duck DNS     |                            [root/acme-dns-01-duckdns](https://git.rootprojects.org/root/acme-dns-01-duckdns.js)                            | |  | ||||||
| |      Gandi       |                              [root/acme-dns-01-gandi](https://git.rootprojects.org/root/acme-dns-01-gandi.js)                              | |  | ||||||
| |     GoDaddy      |                            [root/acme-dns-01-godaddy](https://git.rootprojects.org/root/acme-dns-01-godaddy.js)                            | |  | ||||||
| |    NameCheap     |                          [root/acme-dns-01-namecheap](https://git.rootprojects.org/root/acme-dns-01-namecheap.js)                          | |  | ||||||
| |     Name.com     |                         [root/acme-dns-01-namedotcom](https://git.rootprojects.org/root/acme-dns-01-namedotcom.js)                         | |  | ||||||
| |  Route 53 (AWS)  |                                [hgezim/acme-dsns-01-route53](https://github.com/hgezim/acme-dns-01-route53)                                | |  | ||||||
| |      Vultr       |                              [root/acme-dns-01-vultr](https://git.rootprojects.org/root/acme-dns-01-vultr.js)                              | |  | ||||||
| |       etcd       |                                  [ceecko/le-challenge-etcd](https://github.com/ceecko/le-challenge-etcd)                                   | |  | ||||||
| |        -         |                     **Build Your Own** <br> [acme-dns-01-test](https://git.rootprojects.org/root/acme-dns-01-test.js)                      | |  | ||||||
| |    Full List     | Search [acme-dns-01-](https://www.npmjs.com/search?q=acme-dns-01-) or [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) on npm | |  | ||||||
| 
 |  | ||||||
| ## Account & Certificate Storage |  | ||||||
| 
 |  | ||||||
| |                      |                                                Plugin                                                 | |  | ||||||
| | :------------------: | :---------------------------------------------------------------------------------------------------: | |  | ||||||
| |     **Simplest**     |             [greenlock-store-fs](https://git.rootprojects.org/root/greenlock-store-fs.js)             | |  | ||||||
| | certbot (v2 default) |               [le-store-certbot](https://git.coolaj86.com/coolaj86/le-store-certbot.js)               | |  | ||||||
| |        AWS S3        |                    [gl-store-s3](https://git.rootprojects.org/root/gl-store-s3.js)                    | |  | ||||||
| |        Consul        |      [sebastian-software/le-store-consul](https://github.com/sebastian-software/le-store-consul)      | |  | ||||||
| |      json (fs)       |            [paulgrove/le-store-simple-fs](https://github.com/paulgrove/le-store-simple-fs)            | |  | ||||||
| |        Redis         |            [digitalbazaar/le-store-redis](https://github.com/digitalbazaar/le-store-redis)            | |  | ||||||
| |          -           | Build Your Own <br> [greenlock-store-test](https://git.rootprojects.org/root/greenlock-store-test.js) | |  | ||||||
| |      Full List       |                  Search [le-store-](https://www.npmjs.com/search?q=le-store-) on npm                  | |  | ||||||
| 
 |  | ||||||
| ## Auto-SNI |  | ||||||
| 
 |  | ||||||
| |             |                             Plugin                              | |  | ||||||
| | :---------: | :-------------------------------------------------------------: | |  | ||||||
| | **Default** | [le-sni-auto](https://git.coolaj86.com/coolaj86/le-sni-auto.js) | |  | ||||||
| 
 |  | ||||||
| (you probably wouldn't need or want to replace this) |  | ||||||
| 
 |  | ||||||
| **Bugs**: Please report bugs with the community plugins to the appropriate owner first, then here if you don't get a response. |  | ||||||
| 
 |  | ||||||
| # Usage |  | ||||||
| 
 |  | ||||||
| The oversimplified example was the bait |  | ||||||
| (because everyone seems to want an example that fits in 3 lines, even if it's terribly bad practices), |  | ||||||
| now here's the switch. |  | ||||||
| 
 |  | ||||||
| We have another completely working example that will provides a little more to build off of. |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| git clone https://git.rootprojects.org/root/greenlock-express.js.git |  | ||||||
| pushd greenlock-express.js |  | ||||||
|   npm install |  | ||||||
| popd |  | ||||||
| 
 |  | ||||||
| # replace 'fooCheckDb' in |  | ||||||
| # greenlock-express.js/examples/normal.js |  | ||||||
| 
 |  | ||||||
| node greenlock-express.js/examples/normal.js |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| It looks a little more like this: |  | ||||||
| 
 |  | ||||||
| `serve.js`: |  | ||||||
| 
 |  | ||||||
| ```javascript |  | ||||||
| "use strict"; |  | ||||||
| 
 |  | ||||||
| // returns an instance of greenlock.js with additional helper methods |  | ||||||
| var glx = require("greenlock-express").create({ |  | ||||||
| 	server: "https://acme-v02.api.letsencrypt.org/directory", |  | ||||||
| 	// Note: If at first you don't succeed, stop and switch to staging: |  | ||||||
| 	// https://acme-staging-v02.api.letsencrypt.org/directory |  | ||||||
| 	version: "draft-11", // Let's Encrypt v2 (ACME v2) |  | ||||||
| 
 |  | ||||||
| 	// If you wish to replace the default account and domain key storage plugin |  | ||||||
| 	store: require("le-store-certbot").create({ |  | ||||||
| 		configDir: require("path").join(require("os").homedir(), "acme", "etc"), |  | ||||||
| 		webrootPath: "/tmp/acme-challenges" |  | ||||||
| 	}), |  | ||||||
| 
 |  | ||||||
| 	// Contribute telemetry data to the project |  | ||||||
| 	telemetry: true, |  | ||||||
| 
 |  | ||||||
| 	// the default servername to use when the client doesn't specify |  | ||||||
| 	// (because some IoT devices don't support servername indication) |  | ||||||
| 	servername: "example.com", |  | ||||||
| 
 |  | ||||||
| 	approveDomains: approveDomains |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| var server = glx.listen(80, 443, function() { |  | ||||||
| 	console.log("Listening on port 80 for ACME challenges and 443 for express app."); |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Note: You shouldn't be using the plain HTTP server for anything except, potentially, for error handling |  | ||||||
| on the listen event (if the default print-and-quit behavior doesn't work for your use case). |  | ||||||
| If you need to do that, here's how: |  | ||||||
| 
 |  | ||||||
| ``` |  | ||||||
| var plainServer = server.unencrypted; |  | ||||||
| plainServer.on('error', function (err) { ... }); |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| The Automatic Certificate Issuance is initiated via SNI (`httpsOptions.SNICallback`). |  | ||||||
| For security, domain validation MUST have an approval callback in _production_. |  | ||||||
| 
 |  | ||||||
| ```javascript |  | ||||||
| var http01 = require("le-challenge-fs").create({ webrootPath: "/tmp/acme-challenges" }); |  | ||||||
| function approveDomains(opts, certs, cb) { |  | ||||||
| 	// This is where you check your database and associated |  | ||||||
| 	// email addresses with domains and agreements and such |  | ||||||
| 	// if (!isAllowed(opts.domains)) { return cb(new Error("not allowed")); } |  | ||||||
| 
 |  | ||||||
| 	// The domains being approved for the first time are listed in opts.domains |  | ||||||
| 	// Certs being renewed are listed in certs.altnames (if that's useful) |  | ||||||
| 
 |  | ||||||
| 	// Opt-in to submit stats and get important updates |  | ||||||
| 	opts.communityMember = true; |  | ||||||
| 
 |  | ||||||
| 	// If you wish to replace the default challenge plugin, you may do so here |  | ||||||
| 	opts.challenges = { "http-01": http01 }; |  | ||||||
| 
 |  | ||||||
| 	opts.email = "john.doe@example.com"; |  | ||||||
| 	opts.agreeTos = true; |  | ||||||
| 
 |  | ||||||
| 	// NOTE: you can also change other options such as `challengeType` and `challenge` |  | ||||||
| 	// opts.challengeType = 'http-01'; |  | ||||||
| 	// opts.challenge = require('le-challenge-fs').create({}); |  | ||||||
| 
 |  | ||||||
| 	cb(null, { options: opts, certs: certs }); |  | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ```javascript | And start your server: | ||||||
| // handles acme-challenge and redirects to https |  | ||||||
| require("http") |  | ||||||
| 	.createServer(glx.middleware(require("redirect-https")())) |  | ||||||
| 	.listen(80, function() { |  | ||||||
| 		console.log("Listening for ACME http-01 challenges on", this.address()); |  | ||||||
| 	}); |  | ||||||
| 
 | 
 | ||||||
| var app = require("express")(); | ```bash | ||||||
| app.use("/", function(req, res) { | # Allow non-root node to use ports 80 (HTTP) and 443 (HTTPS) | ||||||
| 	res.end("Hello, World!"); | sudo setcap 'cap_net_bind_service=+ep' $(which node) | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| // handles your app |  | ||||||
| require("https") |  | ||||||
| 	.createServer(glx.httpsOptions, app) |  | ||||||
| 	.listen(443, function() { |  | ||||||
| 		console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address()); |  | ||||||
| 	}); |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| **Security**: | ```bash | ||||||
|  | # `npm start` will call `node ./server.js` by default | ||||||
|  | npm start | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| Greenlock will do a self-check on all domain registrations | ```txt | ||||||
| to prevent you from hitting rate limits. | Greenlock v3.0.0 | ||||||
|  | Greenlock Manager Config File: ~/.config/greenlock/manager.json | ||||||
|  | Greenlock Storage Directory: ~/.config/greenlock/ | ||||||
| 
 | 
 | ||||||
| # API | Listening on 0.0.0.0:80 for ACME challenges and HTTPS redirects | ||||||
|  | Listening on 0.0.0.0:443 for secure traffic | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| This module is an elaborate ruse (to provide an oversimplified example and to nab some SEO). | ## 4. Manage domains | ||||||
| 
 | 
 | ||||||
| The API is actually located at [greenlock.js options](https://git.rootprojects.org/root/greenlock.js) | Management can be done via the **CLI** or the JavaScript [**API**](https://git.rootprojects.org/root/greenlock.js/). | ||||||
| (because all options are simply passed through to `greenlock.js` proper without modification). | Since this is the QuickStart, we'll demo the **CLI**: | ||||||
| 
 | 
 | ||||||
| The only "API" consists of two options, the rest is just a wrapper around `greenlock.js` to take LOC from 15 to 5: | You need to create a Let's Encrypt _subscriber account_, which can be done globally, or per-site. | ||||||
|  | All individuals, and most businesses, should set this globally: | ||||||
| 
 | 
 | ||||||
| - `opts.app` An express app in the format `function (req, res) { ... }` (no `next`). | ```bash | ||||||
| - `server = glx.listen(plainAddr, tlsAddr, onListen)` Accepts port numbers (or arrays of port numbers) to listen on, returns secure server. | # Set a global subscriber account | ||||||
|   - `listen(80, 443)` | npx greenlock config --subscriber-email 'mycompany@example.com' --agree-to-terms true | ||||||
|   - `listen(80, 443, onListenSecure)` | ``` | ||||||
|   - `listen(80, 443, onListenPlain, onListenSecure)` |  | ||||||
|   - `listen('localhost:80', '0.0.0.0:443')` |  | ||||||
|   - `listen('[::1]:80', '[::]:443')` |  | ||||||
|   - `listen('/tmp/glx.plain.sock', '/tmp/glx.secure.sock')` |  | ||||||
| 
 | 
 | ||||||
| Brief overview of some simple options for `greenlock.js`: | <!-- todo print where the key was saved --> | ||||||
| 
 | 
 | ||||||
| - `opts.server` set to https://acme-v02.api.letsencrypt.org/directory in production | A Let's Encrypt SSL certificate has a "Subject" (Primary Domain) and up to 100 "Alternative Names" | ||||||
| - `opts.version` set to `v01` for Let's Encrypt v1 or `draft-11` for Let's Encrypt v2 (mistakenly called ACME v2) | (of which the first _must_ be the subject). | ||||||
| - `opts.email` The default email to use to accept agreements. |  | ||||||
| - `opts.agreeTos` When set to `true`, this always accepts the LetsEncrypt TOS. When a string it checks the agreement url first. |  | ||||||
| - `opts.communityMember` Join the community to get notified of important updates and help make greenlock better |  | ||||||
| - `opts.approveDomains` can be either of: |  | ||||||
|   - An explicit array of allowed domains such as `[ 'example.com', 'www.example.com' ]` |  | ||||||
|   - A callback `function (opts, certs, cb) { cb(null, { options: opts, certs: certs }); }` for setting `email`, `agreeTos`, `domains`, etc (as shown in usage example above) |  | ||||||
| - `opts.renewWithin` is the **maximum** number of days (in ms) before expiration to renew a certificate. |  | ||||||
| - `opts.renewBy` is the **minimum** number of days (in ms) before expiration to renew a certificate. |  | ||||||
| 
 | 
 | ||||||
| ## Supported ACME versions | ```bash | ||||||
|  | # Add a certificate with specific domains | ||||||
|  | npx greenlock add --subject example.com --altnames example.com,www.example.com | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| - Let's Encrypt v1 (aka v01) | <!-- todo print where the cert was saved --> | ||||||
| - Let's Encrypt v2 (aka v02 or ACME draft 11) |  | ||||||
| - ACME draft 11 (ACME v2 is a misnomer) |  | ||||||
| - Wildcard domains (via dns-01 challenges) |  | ||||||
|   - `*.example.com` |  | ||||||
| 
 | 
 | ||||||
| <small>tags: letsencrypt acme free ssl automated https node express.js</small> | This will update the config file (assuming the default fs-based management plugin): | ||||||
|  | 
 | ||||||
|  | `~/.config/greenlock/manager.json`: | ||||||
|  | 
 | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  | 	"subscriberEmail": "letsencrypt-test@therootcompany.com", | ||||||
|  | 	"agreeToTerms": true, | ||||||
|  | 	"sites": { | ||||||
|  | 		"example.com": { | ||||||
|  | 			"subject": "example.com", | ||||||
|  | 			"altnames": ["example.com", "www.example.com"] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | Note: **Localhost**, **Wildcard**, and Certificates for Private Networks require | ||||||
|  | [**DNS validation**](https://git.rootprojects.org/root/greenlock-exp). | ||||||
|  | 
 | ||||||
|  | - DNS Validation | ||||||
|  |   - [**Wildcards**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/wildcards/README.md) | ||||||
|  |   - [**Localhost**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/localhost/README.md) | ||||||
|  |   - [**CI/CD**](https://git.rootprojects.org/root/greenlock-express.js/src/branch/master/examples/ci-cd/README.md) | ||||||
|  | 
 | ||||||
|  | # Full Documentation | ||||||
|  | 
 | ||||||
|  | <!-- | ||||||
|  | - Greenlock CLI | ||||||
|  | - Greenlock JavaScript API | ||||||
|  | --> | ||||||
|  | 
 | ||||||
|  | Most of the documentation is done by use-case examples, as shown up at the top of the README. | ||||||
|  | 
 | ||||||
|  | We're working on more comprehensive documentation for this newly released version. | ||||||
|  | **Please open an issue** with questions in the meantime. | ||||||
|  | 
 | ||||||
|  | # Commercial Support | ||||||
|  | 
 | ||||||
|  | Do you need... | ||||||
|  | 
 | ||||||
|  | - training? | ||||||
|  | - specific features? | ||||||
|  | - different integrations? | ||||||
|  | - bugfixes, on _your_ timeline? | ||||||
|  | - custom code, built by experts? | ||||||
|  | - commercial support and licensing? | ||||||
|  | 
 | ||||||
|  | You're welcome to [contact us](mailto:aj@therootcompany.com) in regards to IoT, On-Prem, | ||||||
|  | Enterprise, and Internal installations, integrations, and deployments. | ||||||
|  | 
 | ||||||
|  | We have both commercial support and commercial licensing available. | ||||||
|  | 
 | ||||||
|  | We also offer consulting for all-things-ACME and Let's Encrypt. | ||||||
| 
 | 
 | ||||||
| # Legal & Rules of the Road | # Legal & Rules of the Road | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user