| 
									
										
										
										
											2018-05-12 08:02:19 +00:00
										 |  |  |  | 
					
						
							| 
									
										
										
										
											2018-05-12 07:46:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 19:35:32 +00:00
										 |  |  | Greenlock™ for Express.js | 
					
						
							| 
									
										
										
										
											2018-04-20 06:43:02 +00:00
										 |  |  | ================= | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 01:00:44 -06:00
										 |  |  | An easy-to-use ACME client for Free SSL and Automated HTTPS. | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-03 00:56:40 +00:00
										 |  |  | | Sponsored by [ppl](https://ppl.family) | | 
					
						
							| 
									
										
										
										
											2018-05-03 00:55:35 +00:00
										 |  |  | [Greenlock™](https://git.coolaj86.com/coolaj86/greenlock.js) for | 
					
						
							|  |  |  | [cli](https://git.coolaj86.com/coolaj86/greenlock-cli.js), | 
					
						
							|  |  |  | [cluster](https://git.coolaj86.com/coolaj86/greenlock-cluster.js), | 
					
						
							|  |  |  | **Express.js**, | 
					
						
							|  |  |  | [Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js), | 
					
						
							|  |  |  | [hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js) | 
					
						
							| 
									
										
										
										
											2018-04-20 06:43:02 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  | Features | 
					
						
							|  |  |  | ======== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   - [x] Automatic HTTPS | 
					
						
							|  |  |  |     - [x] Free SSL | 
					
						
							|  |  |  |     - [x] Free Wildcard SSL | 
					
						
							|  |  |  |     - [x] Multiple domain support (up to 100 altnames per SAN) | 
					
						
							|  |  |  |     - [x] Dynamic Virtual Hosting (vhost) | 
					
						
							|  |  |  |     - [x] Automatical renewal (10 to 14 days before expiration) | 
					
						
							|  |  |  |   - [x] Great ACME support | 
					
						
							|  |  |  |     - [x] ACME draft 11 | 
					
						
							|  |  |  |     - [x] Let's Encrypt v2 | 
					
						
							|  |  |  |     - [x] Let's Encrypt v1 | 
					
						
							|  |  |  |   - [x] Full node.js support | 
					
						
							|  |  |  |     - [x] core https module | 
					
						
							|  |  |  |     - [x] Express.js | 
					
						
							| 
									
										
										
										
											2018-05-10 01:00:44 -06:00
										 |  |  |     - [x] [Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js) | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  |     - [x] [hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js) | 
					
						
							| 
									
										
										
										
											2018-05-11 20:03:02 +00:00
										 |  |  |   - [x] Extensible Plugin Support | 
					
						
							|  |  |  |     - [x] AWS (S3, Route53) | 
					
						
							|  |  |  |     - [x] Azure | 
					
						
							|  |  |  |     - [x] CloudFlare | 
					
						
							| 
									
										
										
										
											2018-05-11 20:27:53 +00:00
										 |  |  |     - [x] Consul | 
					
						
							| 
									
										
										
										
											2018-05-11 20:03:02 +00:00
										 |  |  |     - [x] Digital Ocean | 
					
						
							|  |  |  |     - [x] etcd | 
					
						
							|  |  |  |     - [x] Redis | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | Install | 
					
						
							|  |  |  | ======= | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ```bash | 
					
						
							| 
									
										
										
										
											2017-01-25 15:02:16 -07:00
										 |  |  | npm install --save greenlock-express@2.x | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  | become a `communityMember` | 
					
						
							|  |  |  | ================== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you're the kind of person that likes the kinds of stuff that I do, | 
					
						
							|  |  |  | well, I want to do more of it and I'd like to get you involved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | When you set the `communityMember` option to `true` I save your | 
					
						
							|  |  |  | email and I'm able to inform you when there are mandatory updates | 
					
						
							|  |  |  | (such as with Let's Encrypt v2), notify you of important security issues, | 
					
						
							|  |  |  | give you early access to similar projects, and | 
					
						
							|  |  |  | get your feedback from time to time. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | I'll also get a hash of domain names that receive and renew certificates, | 
					
						
							|  |  |  | which is a metric that has long interested me and may help me in getting | 
					
						
							|  |  |  | non-developers involved in this and future projects. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | QuickStart | 
					
						
							| 
									
										
										
										
											2016-08-15 19:14:57 -04:00
										 |  |  | ========== | 
					
						
							| 
									
										
										
										
											2018-04-23 20:04:07 +00:00
										 |  |  | <!--
 | 
					
						
							| 
									
										
										
										
											2018-04-23 19:55:03 +00:00
										 |  |  | [](https://youtu.be/e8vaR4CEZ5s) | 
					
						
							| 
									
										
										
										
											2018-04-23 20:04:07 +00:00
										 |  |  | --> | 
					
						
							| 
									
										
										
										
											2018-04-23 19:55:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-23 20:02:50 +00:00
										 |  |  | ### Screencast
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Watch the QuickStart demonstration: https://youtu.be/e8vaR4CEZ5s | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * [0:00](https://youtu.be/e8vaR4CEZ5s#t=0) - Intro | 
					
						
							|  |  |  | * [2:22](https://youtu.be/e8vaR4CEZ5s#t=142) - Demonstrating QuickStart Example | 
					
						
							|  |  |  | * [6:37](https://youtu.be/e8vaR4CEZ5s?t=397) - Troubleshooting / Gotchas | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Working Example Code
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:14:39 +00:00
										 |  |  | Here's a completely working example that will get you started. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 08:59:33 +00:00
										 |  |  | ``` | 
					
						
							|  |  |  | git clone https://git.coolaj86.com/coolaj86/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 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:14:39 +00:00
										 |  |  | All you have to do is start the webserver and then visit it at its domain name. | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | `app.js`: | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-25 15:02:16 -07:00
										 |  |  | require('greenlock-express').create({ | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  |   // Let's Encrypt v2 is ACME draft 11 | 
					
						
							|  |  |  |   version: 'draft-11' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // You MUST change 'acme-staging-v02' to 'acme-v02' in production | 
					
						
							| 
									
										
										
										
											2018-04-19 21:37:56 -06:00
										 |  |  | , server: 'https://acme-staging-v02.api.letsencrypt.org/directory'  // staging | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  |   // You MUST change this to a valid email address | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | , email: 'john.doe@example.com' | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  |   // You MUST NOT build clients that accept the ToS without asking the user | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | , agreeTos: true | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  |   // You MUST change these to valid domains | 
					
						
							|  |  |  |   // NOTE: all domains will validated and listed on the certificate | 
					
						
							|  |  |  | , approveDomains: [ 'example.com', 'www.example.com' ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // You MUST have access to write to directory where certs are saved | 
					
						
							|  |  |  |   // ex: /home/foouser/acme/etc | 
					
						
							|  |  |  | , configDir: require('path').join(require('os').homedir(), 'acme', 'etc') | 
					
						
							| 
									
										
										
										
											2016-08-15 21:15:16 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | , app: require('express')().use('/', function (req, res) { | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  |     res.setHeader('Content-Type', 'text/html; charset=utf-8') | 
					
						
							|  |  |  |     res.end('Hello, World!\n\n💚 🔒.js'); | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  |   }) | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  |   // Join the community to get notified of important updates and help me make greenlock better | 
					
						
							|  |  |  | , communityMember: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  | //, debug: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | }).listen(80, 443); | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 04:35:39 +00:00
										 |  |  | ### What if the example didn't work?
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:23:22 +00:00
										 |  |  | Double check the following: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * **Public Facing IP** for `http-01` challenges | 
					
						
							|  |  |  |   * Are you running this *as* a public-facing webserver (good)? or localhost (bad)? | 
					
						
							|  |  |  |   * Does `ifconfig` show a public address (good)? or a private one - 10.x, 192.168.x, etc (bad)? | 
					
						
							|  |  |  |   * If you're on a non-public server, are you using the `dns-01` challenge? | 
					
						
							|  |  |  | * **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** | 
					
						
							|  |  |  |   * You MUST set `approveDomains` to real domains | 
					
						
							|  |  |  |   * 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** | 
					
						
							| 
									
										
										
										
											2018-04-21 02:24:50 +00:00
										 |  |  |   * You MUST be able to bind to ports 80 and 443 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:23:22 +00:00
										 |  |  |   * 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 change the `server` value **in production** | 
					
						
							|  |  |  |   * Shorten the 'acme-staging-v02' part of the server URL to 'acme-v02' | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:09:34 +00:00
										 |  |  | ### Get it working in staging first!
 | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | There are a number of common problems related to system configuration - | 
					
						
							|  |  |  | firewalls, ports, permissions, etc - that you are likely to run up against | 
					
						
							| 
									
										
										
										
											2017-01-25 15:02:16 -07:00
										 |  |  | when using greenlock for your first time. | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | In order to avoid being blocked by hitting rate limits with bad requests, | 
					
						
							| 
									
										
										
										
											2018-04-20 05:29:33 +00:00
										 |  |  | you should always test against the `staging` server | 
					
						
							| 
									
										
										
										
											2018-04-19 21:37:56 -06:00
										 |  |  | (`https://acme-staging-v02.api.letsencrypt.org/directory`) first. | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-30 15:42:33 +00:00
										 |  |  | Plugins | 
					
						
							|  |  |  | ===== | 
					
						
							| 
									
										
										
										
											2018-04-30 15:46:34 +00:00
										 |  |  | **IMPORTANT**: Community plugins may or may not be maintained and working. Please try with the defaults before switching to community plugins. | 
					
						
							| 
									
										
										
										
											2018-04-30 15:42:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | HTTP-01 Challenges | 
					
						
							|  |  |  | ----------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | |                | Plugin    | | 
					
						
							|  |  |  | |:--------------:|:---------:| | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | **Default (fs)** | [le-challenge-fs](https://git.coolaj86.com/coolaj86/le-challenge-fs.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | | AWS S3         | [llun/le-challenge-s3](https://github.com/llun/le-challenge-s3) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:13:16 +00:00
										 |  |  | | Azure          | [kolarcz/node-le-challenge-azure-storage](https://github.com/kolarcz/node-le-challenge-azure-storage) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | - | Build Your Own <br> [le-challenge-http-SPEC](https://git.coolaj86.com/coolaj86/le-challenge-manual.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:11:11 +00:00
										 |  |  | | Full List      | Search [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) on npm | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DNS-01 Challenges | 
					
						
							|  |  |  | ----------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | |                | Plugin    | | 
					
						
							|  |  |  | |:--------------:|:---------:| | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | **Manual (cli)** | [le-challenge-dns](https://git.coolaj86.com/coolaj86/le-challenge-dns.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | | AWS Route 53   | [thadeetrompetter/le-challenge-route53](https://github.com/thadeetrompetter/le-challenge-route53) | | 
					
						
							|  |  |  | | CloudFlare     | [buschtoens/le-challenge-cloudflare](https://github.com/buschtoens/le-challenge-cloudflare) | | 
					
						
							|  |  |  | | CloudFlare     | [llun/le-challenge-cloudflare](https://github.com/llun/le-challenge-cloudflare) | | 
					
						
							|  |  |  | | Digital Ocean  | [bmv437/le-challenge-digitalocean](https://github.com/bmv437/le-challenge-digitalocean) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:03:02 +00:00
										 |  |  | | etcd           | [ceecko/le-challenge-etcd](https://github.com/ceecko/le-challenge-etcd) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | - | Build Your Own <br> [le-challenge-dns-SPEC](https://git.coolaj86.com/coolaj86/le-challenge-dns.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:11:11 +00:00
										 |  |  | | Full List      | Search [le-challenge-](https://www.npmjs.com/search?q=le-challenge-) on npm | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Account & Certificate Storage | 
					
						
							|  |  |  | ----------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | |                | Plugin    | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | |:--------------:|:---------:| | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | **Default (fs)** | [le-store-certbot](https://git.coolaj86.com/coolaj86/le-store-certbot.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | | AWS S3         | [paco3346/le-store-awss3](https://github.com/paco3346/le-store-awss3) | | 
					
						
							|  |  |  | | AWS S3         | [llun/le-store-s3](https://github.com/llun/le-store-s3) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:27:53 +00:00
										 |  |  | | Consul         | [sebastian-software/le-store-consul](https://github.com/sebastian-software/le-store-consul) | | 
					
						
							| 
									
										
										
										
											2018-05-11 19:58:37 +00:00
										 |  |  | | 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) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | | - | Build Your Own <br> [le-store-SPEC](https://git.coolaj86.com/coolaj86/le-store-SPEC.js) | | 
					
						
							| 
									
										
										
										
											2018-05-11 20:11:11 +00:00
										 |  |  | | Full List      | Search [le-store-](https://www.npmjs.com/search?q=le-store-) on npm | | 
					
						
							| 
									
										
										
										
											2018-04-30 15:42:33 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | Auto-SNI | 
					
						
							|  |  |  | -------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | |             | Plugin    | | 
					
						
							|  |  |  | |:-----------:|:---------:| | 
					
						
							|  |  |  | | **Default** | [le-store-certbot](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. | 
					
						
							| 
									
										
										
										
											2018-04-30 15:46:34 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:14:57 -04:00
										 |  |  | Usage | 
					
						
							|  |  |  | ===== | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | 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), | 
					
						
							| 
									
										
										
										
											2018-04-20 08:59:33 +00:00
										 |  |  | 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.coolaj86.com/coolaj86/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: | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | `serve.js`: | 
					
						
							|  |  |  | ```javascript | 
					
						
							|  |  |  | 'use strict'; | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 05:32:15 +00:00
										 |  |  | // returns an instance of greenlock.js with additional helper methods | 
					
						
							| 
									
										
										
										
											2017-01-25 15:02:16 -07:00
										 |  |  | var lex = require('greenlock-express').create({ | 
					
						
							| 
									
										
										
										
											2018-04-19 21:37:56 -06:00
										 |  |  |   // set to https://acme-v02.api.letsencrypt.org/directory in production | 
					
						
							|  |  |  |   server: 'https://acme-staging-v02.api.letsencrypt.org/directory' | 
					
						
							|  |  |  | , version: 'draft-11' // Let's Encrypt v2 (ACME v2) | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:33:22 -06:00
										 |  |  |   // If you wish to replace the default account and domain key storage plugin | 
					
						
							| 
									
										
										
										
											2018-05-11 20:51:22 -06:00
										 |  |  | , store: require('le-store-certbot').create({ | 
					
						
							|  |  |  |     configDir: require('path').join(require('os').homedir(), 'acme', 'etc') | 
					
						
							|  |  |  |   , webrootPath: '/tmp/acme-challenges' | 
					
						
							|  |  |  |   }) | 
					
						
							| 
									
										
										
										
											2016-08-12 03:48:21 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  | , approveDomains: approveDomains | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2016-08-17 09:09:43 -06:00
										 |  |  | ``` | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 07:09:34 +00:00
										 |  |  | The Automatic Certificate Issuance is initiated via SNI (`httpsOptions.SNICallback`). | 
					
						
							|  |  |  | For security, domain validation MUST have an approval callback in *production*. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2018-05-11 20:29:21 -06:00
										 |  |  | var http01 = require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' }); | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  | function approveDomains(opts, certs, cb) { | 
					
						
							|  |  |  |   // This is where you check your database and associated | 
					
						
							|  |  |  |   // email addresses with domains and agreements and such | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:29:21 -06:00
										 |  |  |   // Opt-in to submit stats and get important updates | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  |   opts.communityMember = true; | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-11 20:33:22 -06:00
										 |  |  |   // If you wish to replace the default challenge plugin, you may do so here | 
					
						
							| 
									
										
										
										
											2018-05-11 20:29:21 -06:00
										 |  |  |   opts.challenges = { 'http-01': http01 }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  |   // The domains being approved for the first time are listed in opts.domains | 
					
						
							|  |  |  |   // Certs being renewed are listed in certs.altnames | 
					
						
							|  |  |  |   if (certs) { | 
					
						
							|  |  |  |     opts.domains = certs.altnames; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   else { | 
					
						
							|  |  |  |     opts.email = 'john.doe@example.com'; | 
					
						
							|  |  |  |     opts.agreeTos = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-10-14 13:37:53 -06:00
										 |  |  |   // NOTE: you can also change other options such as `challengeType` and `challenge` | 
					
						
							|  |  |  |   // opts.challengeType = 'http-01'; | 
					
						
							|  |  |  |   // opts.challenge = require('le-challenge-fs').create({}); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:11:10 -06:00
										 |  |  |   cb(null, { options: opts, certs: certs }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:09:43 -06:00
										 |  |  | ```javascript | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | // handles acme-challenge and redirects to https | 
					
						
							| 
									
										
										
										
											2016-08-19 16:22:57 -06:00
										 |  |  | require('http').createServer(lex.middleware(require('redirect-https')())).listen(80, function () { | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  |   console.log("Listening for ACME http-01 challenges on", this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | var app = require('express')(); | 
					
						
							|  |  |  | app.use('/', function (req, res) { | 
					
						
							|  |  |  |   res.end('Hello, World!'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | // handles your app | 
					
						
							| 
									
										
										
										
											2016-08-17 09:08:47 -06:00
										 |  |  | require('https').createServer(lex.httpsOptions, lex.middleware(app)).listen(443, function () { | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  |   console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address()); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2016-08-12 03:02:33 -04:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-17 09:25:07 -06:00
										 |  |  | **Security Warning**: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you don't do proper checks in `approveDomains(opts, certs, cb)` | 
					
						
							|  |  |  | an attacker will spoof SNI packets with bad hostnames and that will | 
					
						
							|  |  |  | cause you to be rate-limited and or blocked from the ACME server. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 19:14:57 -04:00
										 |  |  | API | 
					
						
							|  |  |  | === | 
					
						
							| 
									
										
										
										
											2016-08-12 03:56:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 21:15:16 -04:00
										 |  |  | This module is an elaborate ruse (to provide an oversimplified example and to nab some SEO). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 05:32:15 +00:00
										 |  |  | The API is actually located at [greenlock.js options](https://git.coolaj86.com/coolaj86/greenlock.js) | 
					
						
							|  |  |  | (because all options are simply passed through to `greenlock.js` proper without modification). | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 05:32:15 +00:00
										 |  |  | The only "API" consists of two options, the rest is just a wrapper around `greenlock.js` to take LOC from 15 to 5: | 
					
						
							| 
									
										
										
										
											2016-08-15 19:12:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-15 21:15:16 -04:00
										 |  |  | * `opts.app` An express app in the format `function (req, res) { ... }` (no `next`). | 
					
						
							|  |  |  | * `lex.listen(plainPort, tlsPort)` Accepts port numbers (or arrays of port numbers) to listen on. | 
					
						
							| 
									
										
										
										
											2016-08-12 03:56:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 05:32:15 +00:00
										 |  |  | Brief overview of some simple options for `greenlock.js`: | 
					
						
							| 
									
										
										
										
											2016-08-12 03:56:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-20 05:32:15 +00:00
										 |  |  | * `opts.server` set to https://acme-v02.api.letsencrypt.org/directory in production | 
					
						
							| 
									
										
										
										
											2018-04-19 21:37:56 -06:00
										 |  |  | * `opts.version` set to `v01` for Let's Encrypt v1 or `draft-11` for Let's Encrypt v2 (mistakenly called ACME v2) | 
					
						
							| 
									
										
										
										
											2016-08-15 21:15:16 -04:00
										 |  |  | * `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. | 
					
						
							| 
									
										
										
										
											2018-05-10 01:00:44 -06:00
										 |  |  | * `opts.communityMember` Join the community to get notified of important updates and help make greenlock better | 
					
						
							| 
									
										
										
										
											2016-08-17 09:25:07 -06:00
										 |  |  | * `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) | 
					
						
							| 
									
										
										
										
											2016-08-15 21:15:16 -04:00
										 |  |  | * `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. | 
					
						
							| 
									
										
										
										
											2018-05-03 00:55:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Supported ACME versions
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * Let's Encrypt v1 (aka v01) | 
					
						
							|  |  |  | * Let's Encrypt v2 (aka v02 or ACME draft 11) | 
					
						
							|  |  |  | * ACME draft 11 (ACME v2 is a misnomer) | 
					
						
							| 
									
										
										
										
											2018-05-10 01:00:44 -06:00
										 |  |  | * Wildcard domains (via dns-01 challenges) | 
					
						
							| 
									
										
										
										
											2018-05-10 00:53:45 -06:00
										 |  |  |   * `*.example.com` |