Package Exports
- certnode
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (certnode) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
certnode
Generate Let's Encrypt certificates in Node!
Why?
I wanted to see how difficult it is to generate Let's Encrypt certificates in Node without using an external package like greenlock or exec-ing certbot in child processes.
Essentially this boils down to creating keypairs, signing and sending HTTPS requests to Let's Encrypt's API endpoints. Not a huge lift; however, certnode is pretty limited right now. Extending functionality might be a larger effort.
This was primarily a learning exercise but also an effort to create a package that hopefully makes it easy for others to generate certificates for their domains :)
Install
npm i certnode
Usage
The example code can be found here.
Note: you must control the domain + email address you pass to client.generateCertificate(). Also, be sure to allow inbound HTTP traffic (TCP, port 80) in your firewall rules.
Generate account keys
const certnode = require('certnode')
const fs = require('fs')
const https = require('https')
const client = new certnode.Client()
// Generate fresh account keys for Let's Encrypt
await client.generateAccountKeyPair()Generate certificate for HTTPS server
const { certificate, privateKeyData } = await client.generateCertificate('<domain>', '<email>')
const server = https.createServer({ cert: certificate, key: privateKeyData })
/* register event listeners */
server.listen(443, '0.0.0.0', () => {})Write account keys to filesytem
// Account private key is encrypted with passphrase, if provided.
await client.exportAccountKeyPair('<directory>', '[passphrase]')Write certificate + private key to filesystem
// Certificate private key is encrypted with passphrase, if provided.
await Promise.all([
fs.promises.writeFile('/path/to/certificate', certificate),
certnode.writeKeyToFile('/path/to/privateKey', privateKeyData, '[passphrase]')
])Import account keys
const anotherClient = new certnode.Client()
// If you previously exported with passphrase, provide the same passphrase.
await anotherClient.importAccountKeyPair('<directory>', '[passphrase]')
/* generate certificate with `anotherClient` */Import certificate + private key for HTTPS server
const [certificate, privateKeyData] = await Promise.all([
fs.promises.readFile('/path/to/certificate', 'utf8'),
fs.promises.readFile('/path/to/privateKey', 'utf8')
])
// If you previously exported with passphrase, provide the same passphrase.
const server = https.createServer({
cert: certificate,
key: privateKeyData,
passphrase: '[passphrase]'
})
/* register event listeners */
server.listen(443, '0.0.0.0', () => {})Documentation
To generate the API docs:
npm run docs
Then open ./out/index.html in your browser.
Test
sudo domain=<domain> npm test
The test suite sends HTTPS requests to Let's Encrypt (staging environment) and generates certificates.
Therefore, tests must run from a domain you control, presumably on a VPS. Since certnode attains certificates through HTTP validation, it must run as root so it can listen on port 80. Make sure firewall rules allow inbound HTTP traffic.
Note: if you run tests several times in quick succession, you may be rate-limited by Let's Encrypt.
Linting
npm run lint