greenlock-store-fs.js/README.md

112 lines
3.0 KiB
Markdown

# le-store-fs
A greenlock keypair and certificate storage strategy with wildcard support (simpler successor to le-store-certbot).
# Usage
```js
var greenlock = require('greenlock');
var gl = greenlock.create({
configDir: '~/.config/acme'
, store: require('le-store-fs')
, approveDomains: approveDomains
, ...
});
```
# File System
The default file system layout mirrors that of le-store-certbot in order to make transitioning effortless,
in most situations:
```
acme
├── accounts
│   └── acme-staging-v02.api.letsencrypt.org
│   └── directory
│   └── sites@example.com.json
└── live
├── example.com
│   ├── bundle.pem
│   ├── cert.pem
│   ├── chain.pem
│   ├── fullchain.pem
│   └── privkey.pem
└── www.example.com
├── bundle.pem
├── cert.pem
├── chain.pem
├── fullchain.pem
└── privkey.pem
```
# Wildcards & AltNames
Working with wildcards and multiple altnames requires greenlock >= v2.7.
To do so you must set `opts.subject` and `opts.domains` within the `approvedomains()` callback.
`subject` refers to "the subject of the ssl certificate" as opposed to `domain` which indicates "the domain servername
used in the current request". For single-domain certificates they're always the same, but for multiple-domain
certificates `subject` must be the name no matter what `domain` is receiving a request. `subject` is used as
part of the name of the file storage path where the certificate will be saved (or retrieved).
`domains` should be the list of "altnames" on the certificate, which should include the `subject`.
## Simple Example
```js
function approveDomains(opts) {
// Allow only example.com and *.example.com (such as foo.example.com)
// foo.example.com => *.example.com
var wild = '*.' + opts.domain.split('.').slice(1).join('.');
if ('example.com' !== opts.domain && '*.example.com' !== wild) {
cb(new Error(opts.domain + " is not allowed"));
}
opts.subject = 'example.com';
opts.domains = [ 'example.com', '*.example.com' ];
return Promise.resolve(opts);
}
```
## Realistic Example
```js
function approveDomains(opts, certs, cb) {
var related = getRelated(opts.domain);
if (!related) { cb(new Error(opts.domain + " is not allowed")); };
opts.subject = related.subject;
opts.domains = related.domains;
cb({ options: opts, certs: certs });
}
```
```js
function getRelated(domain) {
var related;
var wild = '*.' + domain.split('.').slice(1).join('.');
if (Object.keys(allAllowedDomains).some(function (k) {
return allAllowedDomains[k].some(function (name) {
if (domain === name || wild === name) {
related = { subject: k, altnames: allAllowedDomains[k] };
return true;
}
});
})) {
return related;
}
}
```
```js
var allAllowedDomains = {
'example.com': ['example.com', '*.example.com']
, 'example.net': ['example.net', '*.example.net']
}
```