diff --git a/README.md b/README.md index 386656c..ec56f26 100644 --- a/README.md +++ b/README.md @@ -119,3 +119,184 @@ The same dissolution from the terminal would be export NODE_TLS_REJECT_UNAUTHORIZED="0" node my-service.js ``` + +# Index + +Other information you might want to know while you're here. + +## Generating an SSL Cert + +Just in case you didn't know, here's how you do it: + +``` +openssl req -new -newkey rsa:2048 -nodes -keyout server.key -out server.csr +``` + +**DO NOT FILL OUT** email address, challenge password, or optional company name + +However, you *should* fill out country name, FULL state name, locality name, organization name. + +*organizational unit* is optional. + +``` +cat server.csr +``` + +That creates a sha-1 hash. + +When you submit that to the likes of RapidSSL you'll get back an X.509 that you should call `server.crt` (at least for the purposes of this mini-tutorial). + +You cannot use "bundled" certificates (`.pem`) with node.js. + +### A single HTTPS server + +Here's a complete working example: + +```javascript +'use strict'; + +var https = require('https') + , fs = require('fs') + , connect = require('connect') + , app = connect() + , sslOptions + , server + , port = 4080 + ; + +require('ssl-root-cas/latest') + .inject() + .addFile(__dirname + '/ssl/Geotrust Cross Root CA.txt') + .addFile(__dirname + '/ssl/Rapid SSL CA.txt') + ; + +sslOptions = { + key: fs.readFileSync('./ssl/server.key') +, cert: fs.readFileSync('./ssl/server.crt') +}; + +app.use('/', function (req, res) { + res.end('

Hello World

'); +}); + +server = https.createServer(sslOptions, app).listen(port, function(){ + console.log('Listening on https://' + server.address().address + ':' + server.address().port); +}); +``` + +### Multiple HTTPS servers using SNI + +I know this works - because I just bought two SSL certs from RapidSSL (through name.com), +a Digital Ocean VPS, +and played around for an hour until it did. + +:-) + +File hierarchy: + +``` +webapps/ +└── vhosts + ├── aj.the.dj + │   └── ssl + │   ├── server.crt + │   └── server.key + ├── ballprovo.com + │   └── ssl + │   ├── server.crt + │   └── server.key + ├── server.js + └── ssl + ├── Geotrust Cross Root CA.txt + └── Rapid SSL CA.txt +``` + + +#### `server.js` + +```javascript +'use strict'; + +var https = require('https') + , http = require('http') + , fs = require('fs') + , crypto = require('crypto') + , connect = require('connect') + , vhost = require('vhost') + + // connect / express app + , app = connect() + + // SSL Server + , secureContexts = {} + , secureOpts + , secureServer + , securePort = 4443 + + // force SSL upgrade server + , server + , port = 4080 + + // the ssl domains I have + , domains = ['aj.the.dj', 'ballprovo.com'] + ; + +require('ssl-root-cas/latest') + .inject() + .addFile(__dirname + '/ssl/Geotrust Cross Root CA.txt') + .addFile(__dirname + '/ssl/Rapid SSL CA.txt') + ; + +function getAppContext(domain) { + // Really you'd want to do this: + // return require(__dirname + '/' + domain + '/app.js'); + + // But for this demo we'll do this: + return connect().use('/', function (req, res) { + console.log('req.vhost', JSON.stringify(req.vhost)); + res.end('

Welcome to ' + domain + '!

'); + }); +} + +domains.forEach(function (domain) { + secureContexts[domain] = crypto.createCredentials({ + key: fs.readFileSync(__dirname + '/' + domain + '/ssl/server.key') + , cert: fs.readFileSync(__dirname + '/' + domain + '/ssl/server.crt') + }).context; + + app.use(vhost('*.' + domain, getAppContext(domain))); + app.use(vhost(domain, getAppContext(domain))); +}); + +// fallback / default domain +app.use('/', function (req, res) { + res.end('

Hello World

'); +}); + +//provide a SNICallback when you create the options for the https server +secureOpts = { + //SNICallback is passed the domain name, see NodeJS docs on TLS + SNICallback: function (domain) { + console.log('SNI:', domain); + return secureContexts[domain]; + } + // fallback / default domain + , key: fs.readFileSync(__dirname + '/aj.the.dj/ssl/server.key') + , cert: fs.readFileSync(__dirname + '/aj.the.dj/ssl/server.crt') +}; + +secureServer = https.createServer(secureOpts, app).listen(securePort, function(){ + console.log("Listening on https://localhost:" + secureServer.address().port); +}); + +server = http.createServer(function (req, res) { + res.setHeader( + 'Location' + , 'https://' + req.headers.host.replace(/:\d+/, ':' + securePort) + ); + res.statusCode = 302; + res.end(); +}).listen(port, function(){ + console.log("Listening on http://localhost:" + server.address().port); +}); +```