greenlock-hapi.js/README.md

2.6 KiB

letsencrypt-hapi

Free SSL and Automatic HTTPS for node.js with hapi.js and other middleware systems via Let's Encrypt

  • Automatic Registration via SNI (httpsOptions.SNICallback)
    • registrations require an approval callback in production
  • Automatic Renewal (around 80 days)
    • renewals are fully automatic and happen in the background, with no downtime
  • Automatic vhost / virtual hosting

All you have to do is start the webserver and then visit it at it's domain name.

Install

npm install --save letsencrypt-express

Pay no attention to the man behind the curtain. (just ignore that the name of the module is letsencrypt-express)

Part 1: Configure LetsEncrypt

'use strict';

var LEX = require('letsencrypt-express').testing();

var lex = LEX.create({
  configDir: require('os').homedir() + '/letsencrypt/etc'
, approveRegistration: function (hostname, cb) {
    cb(null, {
      domains: [hostname]
    , email: 'CHANGE_ME' // user@example.com
    , agreeTos: true
    });
  }
});

WARNING: If you don't do any checks and simply complete approveRegistration callback, an attacker will spoof SNI packets with bad hostnames and that will cause you to be rate-limited and/or blocked from the ACME server. Alternatively, You can run registration manually:

npm install -g letsencrypt-cli

letsencrypt certonly --standalone \
  --config-dir ~/letsencrypt/etc \
  --agree-tos --domains example.com --email user@example.com

# Note: the '--webrootPath' option is also available if you don't want to shut down your webserver to get the cert.

Part 2: Just add Hapi

var hapi = require('hapi');
var https = require('spdy');
var server = new hapi.Server();
var acmeResponder = LEX.createAcmeResponder(lex);
var httpsServer = https.createServer(lex.httpsOptions).listen(443);

server.connection({ listener: httpsServer, autoListen: false, tls: true });

server.route({
  method: 'GET'
, path: '/.well-known/acme-challenge'
, handler: function (request, reply) {
    var req = request.raw.req;
    var res = request.raw.res;

    reply.close(false);
    acmeResponder(req, res);
  }
});

server.route({
  method: 'GET'
, path: '/'
, handler: function (request, reply) {
    reply("Hello, I'm so Hapi!");
  }
});

Part 3: Redirect http to https

var http = require('http');

http.createServer(LEX.createAcmeResponder(lex, function redirectHttps(req, res) {
  res.setHeader('Location', 'https://' + req.headers.host + req.url);
  res.statusCode = 302;
  res.end('<!-- Hello Developer Person! Please use HTTPS instead -->');
})).listen(80);