537883cff5 | ||
---|---|---|
examples | ||
lib | ||
tests | ||
.gitignore | ||
.jshintrc | ||
LICENSE | ||
README.md | ||
greenlock-850x200.png | ||
index.js | ||
package.json |
README.md
🔐 Greenlock™ for node.js
Greenlock provides Free SSL, Free Wildcard SSL, and Fully Automated HTTPS
certificates issued by Let's Encrypt v2 via ACME
| Sponsored by ppl | Greenlock works in the Commandline (cli), as a Web Server, in Web Browsers (WebCrypto), and with node.js (npm).
Features
- Actively Maintained and Supported
- Automatic HTTPS
- Free SSL
- Free Wildcard SSL
- Multiple domain support (up to 100 altnames per SAN)
- Dynamic Virtual Hosting (vhost)
- Automatical renewal (10 to 14 days before expiration)
- Great ACME support via acme.js
- ACME draft 11
- Let's Encrypt v2
- Let's Encrypt v1
- Commandline (cli) Utilities
- Works with
bash
,fish
,zsh
,cmd.exe
,PowerShell
, and more
- Works with
- Browser (cli) Support
- Full node.js support, with modules for
- http/https, Express.js, cluster, hapi, Koa, rill, restify, spdy, etc
- Great for securing your Raspberry Pi
- Extensible Plugin Support
- AWS S3, AWS Route53, Azure, CloudFlare, Consul, Digital Ocean, etcd, Redis
Greenlock.js for Middleware
Documentation for using Greenlock with http/https, Express.js, cluster, hapi, Koa, rill. restify.
Table of Contents
- Install
- Simple Examples
- Example with ALL OPTIONS
- API
- Developer API
- Change History
- License
Install
npm install --save greenlock@2.x
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).
Easy as 1, 2, 3... 4
Greenlock is built to incredibly easy to use, without sacrificing customization or extensibility.
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.
- Automatic HTTPS (for single sites)
- Fully Automatic HTTPS (for multi-domain vhosts)
- Manual HTTPS (for API integration)
Automatic HTTPS
Note: For (fully) automatic HTTPS you may prefer the Express.js module
This works for most people, but it's not as fun as some of the other examples.
Great when
- You only need a limited number of certificates
- You want to use the bare node http and https modules without fluff
////////////////////
// INIT GREENLOCK //
////////////////////
var path = require('path');
var os = require('os')
var Greenlock = require('greenlock');
var acmeEnv = 'staging-';
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-' + acmeEnv + 'v02.api.letsencrypt.org/directory'
, 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);
Fully Automatic HTTPS
Note: For (fully) automatic HTTPS you may prefer the Express.js module
Great when
- You have a growing number of domains
- You're integrating into your own hosting solution
- Customize ACME http-01 or dns-01 challenge
////////////////////
// INIT GREENLOCK //
////////////////////
var path = require('path');
var os = require('os')
var Greenlock = require('greenlock');
var acmeEnv = 'staging-';
var greenlock = Greenlock.create({
version: 'draft-11'
, server: 'https://acme-' + acmeEnv + 'v02.api.letsencrypt.org/directory'
// approve a growing list of domains
, approveDomains: approveDomains
// 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.
var staging = true;
/////////////////////
// SET USER PARAMS //
/////////////////////
var opts = {
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
};
////////////////////
// INIT GREENLOCK //
////////////////////
var greenlock = require('greenlock').create({
version: 'draft-11'
, server: 'https://acme-' + (staging ? 'staging-' : '') + 'v02.api.letsencrypt.org/directory'
, configDir: '/tmp/acme/etc'
});
///////////////////
// GET TLS CERTS //
///////////////////
greenlock.register(opts).then(function (certs) {
console.log(certs);
// privkey, cert, chain, expiresAt, issuedAt, subject, altnames
}, function (err) {
console.error(err);
});
The domain key and ssl certificates you get back can be used in a webserver like this:
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);
Example with ALL OPTIONS
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)
'use strict';
var LE = require('greenlock');
var le;
// Storage Backend
var leStore = require('le-store-certbot').create({
configDir: '~/acme/etc' // or /etc/letsencrypt or wherever
, debug: false
});
// ACME Challenge Handlers
var leHttpChallenge = require('le-challenge-fs').create({
webrootPath: '~/acme/var/' // or template string such as
, debug: false // '/srv/www/:hostname/.well-known/acme-challenge'
});
function leAgree(opts, agreeCb) {
// opts = { email, domains, tosUrl }
agreeCb(null, opts.tosUrl);
}
le = LE.create({
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'
//
// production API
//server: 'https://acme-v02.api.letsencrypt.org/directory'
, store: leStore // handles saving of config, accounts, and certificates
, challenges: {
'http-01': leHttpChallenge // handles /.well-known/acme-challege keys and tokens
}
, challengeType: 'http-01' // default to this challenge type
, agreeToTerms: leAgree // hook to allow user to view and accept LE TOS
//, 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
, debug: false
//, log: function (debug) {console.log.apply(console, args);} // handles debug outputs
});
// If using express you should use the middleware
// app.use('/', le.middleware());
//
// Otherwise you should see the test file for usage of this:
// le.challenges['http-01'].get(opts.domain, key, val, done)
// Check in-memory cache of certificates for the named domain
le.check({ domains: [ 'example.com' ] }).then(function (results) {
if (results) {
// we already have certificates
return;
}
// Register Certificate manually
le.register({
domains: ['example.com'] // CHANGE TO YOUR DOMAIN (list for SANS)
, email: 'user@email.com' // CHANGE TO YOUR EMAIL
, agreeTos: '' // set to tosUrl string (or true) to pre-approve (and skip agreeToTerms)
, rsaKeySize: 2048 // 2048 or higher
, challengeType: 'http-01' // http-01, tls-sni-01, or dns-01
}).then(function (results) {
console.log('success');
}, function (err) {
// Note: you must either use le.middleware() with express,
// manually use le.challenges['http-01'].get(opts, domain, key, val, done)
// or have a webserver running and responding
// to /.well-known/acme-challenge at `webrootPath`
console.error('[Error]: node-greenlock/examples/standalone');
console.error(err.stack);
});
});
Here's what results
looks like:
{ 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
}
API
The full end-user API is exposed in the example above and includes all relevant options.
le.register(opts)
le.check(opts)
Helper Functions
We do expose a few helper functions:
- LE.validDomain(hostname) // returns '' or the hostname string if it's a valid ascii or punycode domain name
TODO fetch domain tld list
Template Strings
The following variables will be tempalted in any strings passed to the options object:
~/
replaced withos.homedir()
i.e./Users/aj
:hostname
replaced with the first domain in the list i.e.example.com
Developer API
If you are developing an le-store-*
or le-challenge-*
plugin you need to be aware of
additional internal API expectations.
IMPORTANT:
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 should be kept in sync.
store implementation
See https://git.coolaj86.com/coolaj86/le-store-SPEC.js
- 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)
challenge implementation
See https://git.coolaj86.com/coolaj86/le-challenge-fs.js
.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
Change History
- v2.2 - Let's Encrypt v2 Support
- v2.2.11 - documentation updates
- v2.2.10 - don't let SNICallback swallow approveDomains errors
6286883fc2
- 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
- v2.1.17 - Nov 5th 2017 migrate back to personal repo
- v2.1.9 - Jan 18th 2017 renamed to greenlock
- v2.0.2 - Aug 9th 2016 update readme
- v2.0.1 - Aug 9th 2016
- major refactor
- simplified API
- modular plugins
- knock out bugs
- v1.5.0 now using letiny-core v2.0.0 and rsa-compat
- v1.4.x I can't remember... but it's better!
- v1.1.0 Added letiny-core, removed node-letsencrypt-python
- v1.0.2 Works with node-letsencrypt-python
- v1.0.0 Thar be dragons
LICENSE
Dual-licensed MIT and Apache-2.0
See LICENSE
Greenlock™ is a trademark of AJ ONeal