🔐 Free SSL, Free Wildcard SSL, and Fully Automated HTTPS for node.js, issued by Let's Encrypt v2 via ACME. Issues and PRs on Github.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

508 lines
17 KiB

!["Greenlock Logo"](https://git.coolaj86.com/coolaj86/greenlock.js/raw/branch/master/logo/greenlock-1063x250.png "Greenlock lock logo and work mark")
6 years ago
!["Greenlock Function"](https://git.coolaj86.com/coolaj86/greenlock.js/raw/branch/master/logo/from-not-secure-to-secure-url-bar.png "from url bar showing not secure to url bar showing secure")
Greenlock™ for node.js
=====
8 years ago
6 years ago
Greenlock provides Free SSL, Free Wildcard SSL, and Fully Automated HTTPS <br>
<small>certificates issued by Let's Encrypt v2 via [ACME](https://git.coolaj86.com/coolaj86/acme-v2.js)</small>
!["Lifetime Downloads"](https://img.shields.io/npm/dt/greenlock.svg "Lifetime Download Count can't be shown")
!["Monthly Downloads"](https://img.shields.io/npm/dm/greenlock.svg "Monthly Download Count can't be shown")
!["Weekly Downloads"](https://img.shields.io/npm/dw/greenlock.svg "Weekly Download Count can't be shown")
!["Stackoverflow Questions"](https://img.shields.io/stackexchange/stackoverflow/t/greenlock.svg "S.O. Question count can't be shown")
6 years ago
| Sponsored by [ppl](https://ppl.family) |
Greenlock works
in the [Commandline](https://git.coolaj86.com/coolaj86/greenlock-cli.js) (cli),
as a [Web Server](https://git.coolaj86.com/coolaj86/greenlock-server.js),
in [Web Browsers](https://git.coolaj86.com/coolaj86/greenlock.html) (WebCrypto),
and with **node.js** ([npm](https://www.npmjs.com/package/greenlock)).
Features
========
- [x] Actively Maintained and Supported
- [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 via [acme.js](https://git.coolaj86.com/coolaj86/acme-v2.js)
- [x] "dry run" with self-diagnostics
6 years ago
- [x] ACME draft 11
- [x] Let's Encrypt v2
- [x] Let's Encrypt v1
- [x] [Commandline](https://git.coolaj86.com/coolaj86/greenlock-cli.js) (cli) Utilities
- [x] Works with `bash`, `fish`, `zsh`, `cmd.exe`, `PowerShell`, and more
6 years ago
- [x] [Browser](https://git.coolaj86.com/coolaj86/greenlock.html) Support
6 years ago
- [x] Full node.js support, with modules for
- [x] [http/https](https://git.coolaj86.com/coolaj86/greenlock-express.js/src/branch/master/examples/https-server.js), [Express.js](https://git.coolaj86.com/coolaj86/greenlock-express.js), [cluster](https://git.coolaj86.com/coolaj86/greenlock-cluster.js), [hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js), [Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js), [rill](https://git.coolaj86.com/coolaj86/greenlock-rill.js), [restify](https://git.coolaj86.com/coolaj86/greenlock-restify.js), spdy, etc
6 years ago
- [x] Great for securing your Raspberry Pi
- [x] Extensible Plugin Support
- [x] AWS S3, AWS Route53, Azure, CloudFlare, Consul, Digital Ocean, etcd, Redis
6 years ago
Greenlock.js for Middleware
------
9 years ago
6 years ago
Documentation for using Greenlock with
[http/https](https://git.coolaj86.com/coolaj86/greenlock-express.js/src/branch/master/examples/https-server.js),
[Express.js](https://git.coolaj86.com/coolaj86/greenlock-express.js),
[cluster](https://git.coolaj86.com/coolaj86/greenlock-cluster.js),
[hapi](https://git.coolaj86.com/coolaj86/greenlock-hapi.js),
[Koa](https://git.coolaj86.com/coolaj86/greenlock-koa.js),
[rill](https://git.coolaj86.com/coolaj86/greenlock-rill.js).
[restify](https://git.coolaj86.com/coolaj86/greenlock-restify.js).
Table of Contents
=================
* Install
* Simple Examples
* Example with ALL OPTIONS
* API
* Developer API
* Change History
* License
9 years ago
6 years ago
Install
=======
6 years ago
```bash
npm install --save greenlock@2.x
```
8 years ago
6 years ago
**Note**: Ignore errors related to `ursa`. It is an optional dependency used when available.
For many people it will not install properly, but it's only necessary on ARM devices (i.e. Raspberry Pi).
### Production vs Staging
If at first you don't succeed, stop and switch to staging.
I've implemented a "dry run" loopback test with self diagnostics
so it's pretty safe to start off with the production URLs
and be far less likely to hit the bad request rate limits.
However, if your first attempt to get a certificate fails
I'd recommend switching to the staging acme server to debug -
unless you're very clear on what the failure was and how to fix it.
```
{ server: 'https://acme-staging-v02.api.letsencrypt.org/directory' }
```
6 years ago
Easy as 1, 2, 3... 4
=====
8 years ago
6 years ago
Greenlock is built to incredibly easy to use, without sacrificing customization or extensibility.
6 years ago
The following examples range from just a few lines of code for getting started,
to more robust examples that you might start with for an enterprise-grade use of the ACME api.
8 years ago
6 years ago
* Automatic HTTPS (for single sites)
* Fully Automatic HTTPS (for multi-domain vhosts)
* Manual HTTPS (for API integration)
6 years ago
Automatic HTTPS
---------------
9 years ago
6 years ago
**Note**: For (fully) automatic HTTPS you may prefer
the [Express.js module](https://git.coolaj86.com/coolaj86/greenlock-express.js)
8 years ago
6 years ago
This works for most people, but it's not as fun as some of the other examples.
8 years ago
6 years ago
Great when
- [x] You only need a limited number of certificates
- [x] You want to use the bare node http and https modules without fluff
```js
////////////////////
// INIT GREENLOCK //
////////////////////
var path = require('path');
var os = require('os')
var Greenlock = require('greenlock');
8 years ago
6 years ago
var greenlock = Greenlock.create({
agreeTos: true // Accept Let's Encrypt v2 Agreement
, email: 'user@example.com' // IMPORTANT: Change email and domains
, approveDomains: [ 'example.com' ]
, communityMember: false // Optionally get important updates (security, api changes, etc)
// and submit stats to help make Greenlock better
, version: 'draft-11'
, server: 'https://acme-v02.api.letsencrypt.org/directory'
6 years ago
, configDir: path.join(os.homedir(), 'acme/etc')
});
////////////////////
// CREATE SERVERS //
////////////////////
var redir = require('redirect-https')();
require('http').createServer(greenlock.middleware(redir)).listen(80);
require('https').createServer(greenlock.tlsOptions, function (req, res) {
res.end('Hello, Secure World!');
}).listen(443);
9 years ago
```
6 years ago
Fully Automatic HTTPS
------------
6 years ago
**Note**: For (fully) automatic HTTPS you may prefer
the [Express.js module](https://git.coolaj86.com/coolaj86/greenlock-express.js)
9 years ago
6 years ago
Great when
9 years ago
6 years ago
- [x] You have a growing number of domains
- [x] You're integrating into your own hosting solution
- [x] Customize ACME http-01 or dns-01 challenge
8 years ago
6 years ago
```js
////////////////////
// INIT GREENLOCK //
////////////////////
8 years ago
6 years ago
var path = require('path');
var os = require('os')
var Greenlock = require('greenlock');
var greenlock = Greenlock.create({
version: 'draft-11'
, server: 'https://acme-v02.api.letsencrypt.org/directory'
6 years ago
// approve a growing list of domains
, approveDomains: approveDomains
6 years ago
// If you wish to replace the default account and domain key storage plugin
, store: require('le-store-certbot').create({
configDir: path.join(os.homedir(), 'acme/etc')
, webrootPath: '/tmp/acme-challenges'
})
});
/////////////////////
// APPROVE DOMAINS //
/////////////////////
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
// 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 };
// 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;
}
// 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 });
}
////////////////////
// CREATE SERVERS //
////////////////////
var redir = require('redirect-https')();
require('http').createServer(greenlock.middleware(redir)).listen(80);
require('https').createServer(greenlock.tlsOptions, function (req, res) {
res.end('Hello, Secure World!');
}).listen(443);
```
Manual HTTPS
-------------
Here's a taste of the API that you might use if building a commandline tool or API integration
that doesn't use node's SNICallback.
```
/////////////////////
// SET USER PARAMS //
/////////////////////
8 years ago
var opts = {
6 years ago
domains: [ 'example.com' // CHANGE EMAIL AND DOMAINS
, 'www.example.com' ]
, email: 'user@example.com'
, agreeTos: true // Accept Let's Encrypt v2 Agreement
, communityMember: true // Help make Greenlock better by submitting
// stats and getting updates
};
6 years ago
////////////////////
// INIT GREENLOCK //
////////////////////
var greenlock = require('greenlock').create({
version: 'draft-11'
, server: 'https://acme-v02.api.letsencrypt.org/directory'
6 years ago
, configDir: '/tmp/acme/etc'
});
///////////////////
// GET TLS CERTS //
///////////////////
greenlock.register(opts).then(function (certs) {
8 years ago
console.log(certs);
// privkey, cert, chain, expiresAt, issuedAt, subject, altnames
}, function (err) {
console.error(err);
});
8 years ago
```
6 years ago
The domain key and ssl certificates you get back can be used in a webserver like this:
8 years ago
6 years ago
```js
var tlsOptions = { key: certs.privkey, cert: certs.cert + '\r\n' + certs.chain };
require('https').createServer(tlsOptions, function (req, res) {
res.end('Hello, Secure World!');
}).listen(443);
8 years ago
```
6 years ago
Example with ALL OPTIONS
=========
9 years ago
8 years ago
The configuration consists of 3 components:
* Storage Backend (search npm for projects starting with 'le-store-')
* ACME Challenge Handlers (search npm for projects starting with 'le-challenge-')
* Letsencryt Config (this is all you)
9 years ago
9 years ago
```javascript
8 years ago
'use strict';
6 years ago
var Greenlock = require('greenlock');
var greenlock;
9 years ago
9 years ago
8 years ago
// Storage Backend
var leStore = require('le-store-certbot').create({
configDir: '~/acme/etc' // or /etc/letsencrypt or wherever
8 years ago
, debug: false
});
9 years ago
8 years ago
// ACME Challenge Handlers
7 years ago
var leHttpChallenge = require('le-challenge-fs').create({
webrootPath: '~/acme/var/' // or template string such as
8 years ago
, debug: false // '/srv/www/:hostname/.well-known/acme-challenge'
});
9 years ago
8 years ago
function leAgree(opts, agreeCb) {
// opts = { email, domains, tosUrl }
agreeCb(null, opts.tosUrl);
9 years ago
}
9 years ago
6 years ago
greenlock = Greenlock.create({
6 years ago
version: 'draft-11' // 'draft-11' or 'v01'
// 'draft-11' is for Let's Encrypt v2 otherwise known as ACME draft 11
// 'v02' is an alias for 'draft-11'
// 'v01' is for the pre-spec Let's Encrypt v1
//
// staging API
//server: 'https://acme-staging-v02.api.letsencrypt.org/directory'
6 years ago
//
// production API
server: 'https://acme-v02.api.letsencrypt.org/directory'
6 years ago
8 years ago
, store: leStore // handles saving of config, accounts, and certificates
7 years ago
, challenges: {
'http-01': leHttpChallenge // handles /.well-known/acme-challege keys and tokens
}
, challengeType: 'http-01' // default to this challenge type
8 years ago
, agreeToTerms: leAgree // hook to allow user to view and accept LE TOS
8 years ago
//, sni: require('le-sni-auto').create({}) // handles sni callback
// renewals happen at a random time within this window
, renewWithin: 14 * 24 * 60 * 60 * 1000 // certificate renewal may begin at this time
, renewBy: 10 * 24 * 60 * 60 * 1000 // certificate renewal should happen by this time
8 years ago
, debug: false
8 years ago
//, log: function (debug) {console.log.apply(console, args);} // handles debug outputs
8 years ago
});
9 years ago
9 years ago
8 years ago
// If using express you should use the middleware
6 years ago
// app.use('/', greenlock.middleware());
8 years ago
//
// Otherwise you should see the test file for usage of this:
6 years ago
// greenlock.challenges['http-01'].get(opts.domain, key, val, done)
9 years ago
8 years ago
// Check in-memory cache of certificates for the named domain
6 years ago
greenlock.check({ domains: [ 'example.com' ] }).then(function (results) {
8 years ago
if (results) {
// we already have certificates
return;
}
9 years ago
8 years ago
8 years ago
// Register Certificate manually
6 years ago
greenlock.register({
8 years ago
domains: ['example.com'] // CHANGE TO YOUR DOMAIN (list for SANS)
, email: 'user@email.com' // CHANGE TO YOUR EMAIL
8 years ago
, agreeTos: '' // set to tosUrl string (or true) to pre-approve (and skip agreeToTerms)
8 years ago
, rsaKeySize: 2048 // 2048 or higher
, challengeType: 'http-01' // http-01, tls-sni-01, or dns-01
}).then(function (results) {
console.log('success');
}, function (err) {
6 years ago
// Note: you must either use greenlock.middleware() with express,
// manually use greenlock.challenges['http-01'].get(opts, domain, key, val, done)
8 years ago
// or have a webserver running and responding
// to /.well-known/acme-challenge at `webrootPath`
console.error('[Error]: node-greenlock/examples/standalone');
8 years ago
console.error(err.stack);
});
9 years ago
8 years ago
});
9 years ago
```
8 years ago
Here's what `results` looks like:
9 years ago
```javascript
8 years ago
{ privkey: '' // PEM encoded private key
, cert: '' // PEM encoded cert
, chain: '' // PEM encoded intermediate cert
, issuedAt: 0 // notBefore date (in ms) parsed from cert
, expiresAt: 0 // notAfter date (in ms) parsed from cert
, subject: '' // example.com
, altnames: [] // example.com,www.example.com
8 years ago
}
9 years ago
```
8 years ago
API
---
9 years ago
8 years ago
The full end-user API is exposed in the example above and includes all relevant options.
9 years ago
8 years ago
```
6 years ago
greenlock.register(opts)
greenlock.check(opts)
8 years ago
```
8 years ago
### Helper Functions
9 years ago
8 years ago
We do expose a few helper functions:
9 years ago
6 years ago
* Greenlock.validDomain(hostname) // returns '' or the hostname string if it's a valid ascii or punycode domain name
9 years ago
8 years ago
TODO fetch domain tld list
9 years ago
### Template Strings
The following variables will be tempalted in any strings passed to the options object:
* `~/` replaced with `os.homedir()` i.e. `/Users/aj`
8 years ago
* `:hostname` replaced with the first domain in the list i.e. `example.com`
8 years ago
Developer API
-------------
9 years ago
8 years ago
If you are developing an `le-store-*` or `le-challenge-*` plugin you need to be aware of
additional internal API expectations.
9 years ago
8 years ago
**IMPORTANT**:
9 years ago
8 years ago
Use `v2.0.0` as your initial version - NOT v0.1.0 and NOT v1.0.0 and NOT v3.0.0.
This is to indicate that your module is compatible with v2.x of node-greenlock.
Since the public API for your module is defined by node-greenlock the major version
8 years ago
should be kept in sync.
8 years ago
### store implementation
9 years ago
7 years ago
See <https://git.coolaj86.com/coolaj86/le-store-SPEC.js>
8 years ago
* getOptions()
* accounts.
* checkKeypair(opts, cb)
* check(opts, cb)
* setKeypair(opts, keypair, cb)
* set(opts, reg, cb)
* certificates.
* checkKeypair(opts, cb)
* check(opts, cb)
* setKeypair(opts, keypair, cb)
* set(opts, reg, cb)
8 years ago
### challenge implementation
9 years ago
7 years ago
See https://git.coolaj86.com/coolaj86/le-challenge-fs.js
9 years ago
8 years ago
* `.set(opts, domain, key, value, cb);` // opts will be saved with domain/key
* `.get(opts, domain, key, cb);` // opts will be retrieved by domain/key
* `.remove(opts, domain, key, cb);` // opts will be retrieved by domain/key
9 years ago
9 years ago
Change History
==============
* v2.2 - Let's Encrypt v2 Support
6 years ago
* v2.2.11 - documentation updates
* v2.2.10 - don't let SNICallback swallow approveDomains errors 6286883fc2a6ebfff711a540a2e4d92f3ac2907c
* v2.2.8 - communityMember option support
* v2.2.7 - bugfix for wildcard support
* v2.2.5 - node v6.x compat
* v2.2.4 - don't promisify all of `dns`
* v2.2.3 - `renewWithin` default to 14 days
* v2.2.2 - replace git dependency with npm
* v2.2.1 - April 2018 **Let's Encrypt v2** support
7 years ago
* v2.1.17 - Nov 5th 2017 migrate back to personal repo
* v2.1.9 - Jan 18th 2017 renamed to greenlock
8 years ago
* v2.0.2 - Aug 9th 2016 update readme
* v2.0.1 - Aug 9th 2016
8 years ago
* major refactor
* simplified API
8 years ago
* modular plugins
8 years ago
* knock out bugs
8 years ago
* v1.5.0 now using letiny-core v2.0.0 and rsa-compat
* v1.4.x I can't remember... but it's better!
9 years ago
* v1.1.0 Added letiny-core, removed node-letsencrypt-python
* v1.0.2 Works with node-letsencrypt-python
* v1.0.0 Thar be dragons
9 years ago
9 years ago
LICENSE
=======
Dual-licensed MIT and Apache-2.0
See LICENSE
6 years ago
Greenlock&trade; is a trademark of AJ ONeal