2016-08-15 23:12:39 +00:00
[![Join the chat at https://gitter.im/Daplie/letsencrypt-express ](https://badges.gitter.im/Daplie/letsencrypt-express.svg )](https://gitter.im/Daplie/letsencrypt-express?utm_source=badge& utm_medium=badge& utm_campaign=pr-badge& utm_content=badge)
2016-08-16 20:15:47 +00:00
| [letsencrypt (lib) ](https://github.com/Daplie/node-letsencrypt )
2016-08-15 23:12:39 +00:00
| [letsencrypt-cli ](https://github.com/Daplie/letsencrypt-cli )
| **letsencrypt-express**
2016-08-16 17:20:51 +00:00
| [letsencrypt-cluster ](https://github.com/Daplie/letsencrypt-cluster )
2016-08-15 23:12:39 +00:00
| [letsencrypt-koa ](https://github.com/Daplie/letsencrypt-koa )
| [letsencrypt-hapi ](https://github.com/Daplie/letsencrypt-hapi )
|
letsencrypt-express
2016-08-12 07:02:33 +00:00
===================
2016-08-10 07:43:11 +00:00
2016-08-15 23:12:39 +00:00
Free SSL and managed or automatic HTTPS for node.js with Express, Koa, Connect, Hapi, and all other middleware systems.
* Automatic Registration via SNI (`httpsOptions.SNICallback`)
* **registrations** require an **approval callback** in *production*
* Automatic Renewal (around 80 days)
* **renewals** are *fully automatic* and happen in the *background* , with **no downtime**
* Automatic vhost / virtual hosting
All you have to do is start the webserver and then visit it at it's domain name.
Help Wanted
-----------
There are a number of easy-to-complete features that are up for grabs.
(mostly requiring either tracing some functions and doing some console.log-ing
or simply updating docs and getting tests to pass so that certain plugins accept
and return the right type of objects to complete the implementation
of certain plugins).
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
If you've got some free cycles to help, I can guide you through the process,
I'm just still too busy to do it all myself right now and nothing is breaking.
Email me < aj @ daplie . com > if you want to help.
2016-08-12 07:02:33 +00:00
Install
=======
```bash
2016-08-15 23:12:39 +00:00
npm install --save letsencrypt-express@2.x
2016-08-12 07:02:33 +00:00
```
2016-08-30 14:54:48 +00:00
**Important**: Use node v4.5+ or v6.x, node < = v4.4 has a [known bug ](https://github.com/nodejs/node/issues/8053 ) in the `Buffer` implementation.
2016-08-15 23:12:39 +00:00
QuickStart
2016-08-15 23:14:57 +00:00
==========
2016-08-12 07:02:33 +00:00
2016-08-16 17:05:41 +00:00
Here's a completely working example that will get you started:
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
`app.js` :
2016-08-12 07:02:33 +00:00
```javascript
'use strict';
2016-08-15 23:12:39 +00:00
require('letsencrypt-express').create({
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
server: 'staging'
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
, email: 'john.doe@example.com'
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
, agreeTos: true
2016-08-12 07:02:33 +00:00
2016-08-17 15:25:07 +00:00
, approveDomains: [ 'example.com' ]
2016-08-16 01:15:16 +00:00
2016-08-15 23:12:39 +00:00
, app: require('express')().use('/', function (req, res) {
res.end('Hello, World!');
})
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
}).listen(80, 443);
2016-08-12 07:02:33 +00:00
```
2016-08-15 23:12:39 +00:00
Certificates will be stored in `~/letsencrypt` .
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
**Important**:
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
You must set `server` to `https://acme-v01.api.letsencrypt.org/directory` **after**
you have tested that your setup works.
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
Why You Must Use 'staging' First
--------------------------------
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
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 letsencrypt for your first time.
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
In order to avoid being blocked by hitting rate limits with bad requests,
you should always test against the `'staging'` server
(`https://acme-staging.api.letsencrypt.org/directory`) first.
2016-08-12 07:02:33 +00:00
2016-08-17 15:25:07 +00:00
Migrating from v1.x
===================
Whereas v1.x had a few hundred lines of code, v2.x is a single small file of about 50 lines.
2016-08-18 19:07:55 +00:00
A few important things to note:
2016-08-19 22:29:31 +00:00
* Delete your v1.x `~/letsencrypt` directory, otherwise you get this:
* `{ type: 'urn:acme:error:malformed', detail: 'Parse error reading JWS', status: 400 }`
2016-08-18 19:07:55 +00:00
* `approveRegistration` has been replaced by `approveDomains`
* All of the behavior has moved to the various plugins, which each have their own options
* Use https and http directly, don't rely on the silly `.listen()` helper. It's just there for looks.
2016-08-17 15:25:07 +00:00
2016-08-15 23:14:57 +00:00
Usage
=====
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00: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),
now here's the switch:
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
`serve.js` :
```javascript
'use strict';
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
// returns an instance of node-letsencrypt with additional helper methods
var lex = require('letsencrypt-express').create({
2016-08-15 23:15:57 +00:00
// set to https://acme-v01.api.letsencrypt.org/directory in production
2016-08-15 23:12:39 +00:00
server: 'staging'
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
// If you wish to replace the default plugins, you may do so here
//
2016-08-19 19:31:37 +00:00
, challenges: { 'http-01': require('le-challenge-fs').create({ webrootPath: '/tmp/acme-challenges' }) }
2016-08-18 06:27:47 +00:00
, store: require('le-store-certbot').create({ webrootPath: '/tmp/acme-challenges' })
2016-08-18 18:58:40 +00:00
// You probably wouldn't need to replace the default sni handler
// See https://github.com/Daplie/le-sni-auto if you think you do
//, sni: require('le-sni-auto').create({})
2016-08-12 07:48:21 +00:00
2016-08-17 15:11:10 +00:00
, approveDomains: approveDomains
2016-08-15 23:12:39 +00:00
});
2016-08-17 15:09:43 +00:00
```
2016-08-12 07:02:33 +00:00
2016-08-17 15:11:10 +00:00
```javascript
function approveDomains(opts, certs, cb) {
// This is where you check your database and associated
// email addresses with domains and agreements and such
// 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 19:37:53 +00: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 15:11:10 +00:00
cb(null, { options: opts, certs: certs });
}
```
2016-08-12 07:02:33 +00:00
2016-08-17 15:09:43 +00:00
```javascript
2016-08-15 23:12:39 +00:00
// handles acme-challenge and redirects to https
2016-08-19 22:22:57 +00:00
require('http').createServer(lex.middleware(require('redirect-https')())).listen(80, function () {
2016-08-15 23:12:39 +00:00
console.log("Listening for ACME http-01 challenges on", this.address());
});
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
var app = require('express')();
app.use('/', function (req, res) {
res.end('Hello, World!');
});
2016-08-12 07:02:33 +00:00
2016-08-15 23:12:39 +00:00
// handles your app
2016-08-17 15:08:47 +00:00
require('https').createServer(lex.httpsOptions, lex.middleware(app)).listen(443, function () {
2016-08-15 23:12:39 +00:00
console.log("Listening for ACME tls-sni-01 challenges and serve app on", this.address());
});
2016-08-12 07:02:33 +00:00
```
2016-08-17 15:25:07 +00: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 23:14:57 +00:00
API
===
2016-08-12 07:56:19 +00:00
2016-08-16 01:15:16 +00:00
This module is an elaborate ruse (to provide an oversimplified example and to nab some SEO).
The API is actually located at [node-letsencrypt options ](https://github.com/Daplie/node-letsencrypt )
(because all options are simply passed through to `node-letsencrypt` proper without modification).
2016-08-15 23:12:39 +00:00
2016-08-16 01:15:16 +00:00
The only "API" consists of two options, the rest is just a wrapper around `node-letsencrypt` to take LOC from 15 to 5:
2016-08-15 23:12:39 +00:00
2016-08-16 01:15:16 +00: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 07:56:19 +00:00
2016-08-16 01:15:16 +00:00
Brief overview of some simple options for `node-letsencrypt` :
2016-08-12 07:56:19 +00:00
2016-08-16 01:15:16 +00:00
* `opts.server` set to https://acme-v01.api.letsencrypt.org/directory in production
* `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.
2016-08-17 15:25:07 +00: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-16 01:15:16 +00: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.