# [greenlock-store-fs](https://git.rootprojects.org/root/greenlock-store-fs.js) | A [Root](https://rootprojects.org) project A keypair and certificate storage strategy for Greenlock v2.7+ (and v3). The (much simpler) successor to le-store-certbot. Works with all ACME (Let's Encrypt) SSL certificate sytles: - [x] single domains - [x] multiple domains (SANs, AltNames) - [x] wildcards - [x] private / localhost domains # Usage **Global** config: ```js greenlock.manager.defaults({ store: { module: "greenlock-store-fs", basePath: "~/.config/greenlock" } }); ``` **Per-site** config: ```js greenlock.add({ subject: "example.com", altnames: ["example.com", "www.example.com"], store: { module: "greenlock-store-fs", basePath: "~/.config/greenlock" } }); ``` # File System The default file system layout mirrors that of certbot (python Let's Encrypt implementation) and the prior le-store-certbot in order to make transitioning effortless. The default structure looks like this: ```txt .config └── greenlock ├── accounts │   └── acme-staging-v02.api.letsencrypt.org │   └── directory │   └── sites@example.com.json ├── staging │ └── (same as live) └── 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 ``` # Internal Implementation Details You **DO NOT NEED TO KNOW** these details. They're provided for the sake of understanding what happens "under the hood" to help you make better choices "in the seat". # Parameters | parameters | example | notes | | ----------------- | -------------------------------------------------------- | ---------------- | | `env` | `staging` or `live` | - | | `directoryUrl` | `https://acme-staging-v02.api.letsencrypt.org/directory` | - | | `keypair` | `{ privateKeyPem, privateKeyJwk }` | | | `account` | `{ id: "an-arbitrary-id" }` | account only | | `subscriberEmail` | `webhost@example.com` | account only | | `certificate` | `{ id: "an-arbitrary-id" }` | certificate only | | `subject` | `example.com` | certificate only | | `pems` | `{ privkey, cert, chain, issuedAt, expiresAt }` | certificate only | ### Account Keypair ```js accounts.setKeypair = async function({ env, basePath, directoryUrl, email, account }) { var id = account.id || email; var serverDir = directoryUrl.replace("https://", ""); }; ``` ```js accounts.checkKeypair = async function({ env, basePath, directoryUrl, email, account }) { var id = account.id || email; var serverDir = directoryUrl.replace("https://", ""); return { privateKeyPem, privateKeyJwk }; }; ``` ### Certificate Keypair ```js certificate.setKeypair = async function({ env, basePath, directoryUrl, subject, certificate }) { var id = account.id || email; env = env || directoryUrl.replace("https://", ""); }; ``` ```js certificate.checkKeypair = async function({ env, basePath, directoryUrl, subject, certificate }) { var id = account.id || email; env = env || directoryUrl.replace("https://", ""); return { privateKeyPem, privateKeyJwk }; }; ``` ### Certificate PEMs ```js certificate.set = async function({ env, basePath, directoryUrl, subject, certificate, pems }) { var id = account.id || email; env = env || directoryUrl.replace("https://", ""); }; ``` ```js certificate.check = async function({ env, basePath, directoryUrl, subject, certificate }) { var id = account.id || email; env = env || directoryUrl.replace("https://", ""); return { privkey, cert, chain, issuedAt, expiresAt }; }; ```