-
-
Save achingbrain/8d9a00190f2e13182579d26d138f5b4a to your computer and use it in GitHub Desktop.
How to get an SSL cert for our home internet connection
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const NatAPI = require('nat-api') | |
const acme = require('acme-client') | |
const { promisify } = require('util') | |
const dns = require('dns') | |
const http = require('http') | |
const nat = new NatAPI() | |
const externalIp = promisify(nat.externalIp.bind(nat)) | |
const mapPort = promisify(nat.map.bind(nat)) | |
const reverseLookup = promisify(dns.reverse.bind(dns)) | |
// Uses UPnP to figure out our external IP address, then does a reverse DNS lookup | |
// on that IP to get our ISP-assigned a domain name, then uses Let's Encrypt to | |
// create an SSL certificate for that domain name. We can then use that SSL certificate | |
// elsewhere to create a WSS transport, add that address to our Announce list and | |
// make the network more usable by browser IPFS nodes. | |
async function main () { | |
const accountEmail = 'herp@derp.com' | |
const accountPrivateKey = await acme.forge.createPrivateKey() | |
// Get our external IP | |
const external = await externalIp() | |
// Do a reverse DNS lookup | |
const [ domain ] = await reverseLookup(external) | |
// High local port to listen on | |
const PORT = 44032 | |
// Forward port 80 on our router to high local port | |
await mapPort({ | |
publicPort: 80, | |
privatePort: PORT, | |
ttl: 1800, | |
protocol: 'TCP' | |
}) | |
// Init client | |
const client = new acme.Client({ | |
directoryUrl: acme.directory.letsencrypt.production, | |
accountKey: accountPrivateKey | |
}) | |
// Create private key for CSR | |
const certificatePrivateKey = await acme.forge.createPrivateKey() | |
// Create CSR | |
const [key, csr] = await acme.forge.createCsr({ | |
commonName: domain, | |
altNames: [] | |
}, certificatePrivateKey) | |
// Will respond to auth challenge | |
let server | |
// Certificate | |
const cert = await client.auto({ | |
csr, | |
email: accountEmail, | |
termsOfServiceAgreed: true, | |
challengePriority: ['http-01'], | |
skipChallengeVerification: true, | |
async challengeCreateFn (authz, challenge, keyAuthorization) { | |
server = http.createServer((req, res)=> { | |
// Respond to challenge | |
if (req.url === `/.well-known/acme-challenge/${challenge.token}`) { | |
res.writeHead(200, {'Content-Type': 'application/octet-stream'}) | |
res.end(keyAuthorization) | |
return | |
} | |
// Ignore everything else | |
res.writeHead(404) | |
res.end() | |
}) | |
return new Promise((resolve) => { | |
server.listen({ | |
port: PORT | |
}, () => { | |
resolve() | |
}) | |
}) | |
}, | |
async challengeRemoveFn () { | |
server.close() | |
} | |
}) | |
// `cert` is a pem-format certificate chain - use it to create WSS transport | |
console.info(cert) | |
// Remove router port mapping | |
nat.destroy() | |
} | |
main().catch(err => { | |
console.error(err) | |
process.exit(1) | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
npm install nat-api acme-client
index.js
node .