Given an SSL key and certificate, how does one create an HTTPS service?
-
2I used restify.js instead of express.js, but the idea is the same. Here's how I set up a node.js server that accepts both HTTP and HTTPS qugstart.com/blog/node-js/…awaage– awaage2012-02-28 22:55:45 +00:00Commented Feb 28, 2012 at 22:55
-
2without express and with the newest version of node - look here: stackoverflow.com/a/21809393/388026Philipp Kyeck– Philipp Kyeck2014-04-09 07:04:06 +00:00Commented Apr 9, 2014 at 7:04
-
1What happened to this question? The answers imply that it was originally about express.js.doug65536– doug655362015-10-04 04:42:54 +00:00Commented Oct 4, 2015 at 4:42
-
it's trivial to create a valid, self-signed SSL cert and launch an HTTPS server, just a few stepsLloyd– Lloyd2015-12-09 21:26:45 +00:00Commented Dec 9, 2015 at 21:26
-
4Its a bit late but if someone need a complete nodejs https tutorial, can find here: programmerblog.net/nodejs-https-serverM I– M I2018-06-10 19:07:17 +00:00Commented Jun 10, 2018 at 19:07
9 Answers
The Express API doc spells this out pretty clearly.
Additionally this answer gives the steps to create a self-signed certificate.
I have added some comments and a snippet from the Node.js HTTPS documentation:
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
// This line is from the Node.js HTTPS documentation.
var options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.cert')
};
// Create a service (the app object is just a callback).
var app = express();
// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
13 Comments
options first in https.createServer, to avoid cryptic errors.For Node 0.3.4 and above all the way up to the current LTS (v21 at the time of this edit), https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener has all the example code you need:
const https = require('node:https');
const fs = require('node:fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
Note that if want to use Let's Encrypt's certificates using the certbot tool, the private key is called privkey.pem and the certificate is called fullchain.pem:
const certDir = `/etc/letsencrypt/live`;
const domain = `YourDomainName`;
const options = {
key: fs.readFileSync(`${certDir}/${domain}/privkey.pem`),
cert: fs.readFileSync(`${certDir}/${domain}/fullchain.pem`)
};
8 Comments
setSecure is deprecated. Check this out instead stackoverflow.com/questions/5136353/node-js-https-secure-errorFound this question while googling "node https" but the example in the accepted answer is very old - taken from the docs of the current (v21) version of node, it should look like this:
const https = require('node:https');
const fs = require('node:fs');
const options = {
key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem'),
};
https.createServer(options, (req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
6 Comments
*.pem)? I tried following this page, but when opening localhost:8000 in the browser, no data is received (just loading...).openssl, then in cmd prompt, type openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3001https://localhost:8080. HTTP is NOT HTTPS.The above answers are good but with Express and node this will work fine.
Since express create the app for you, I'll skip that here.
var express = require('express')
, fs = require('fs')
, routes = require('./routes');
var privateKey = fs.readFileSync('cert/key.pem').toString();
var certificate = fs.readFileSync('cert/certificate.pem').toString();
// To enable HTTPS
var app = module.exports = express.createServer({key: privateKey, cert: certificate});
3 Comments
module.exports? There's no need for thatThe minimal setup for an HTTPS server in Node.js would be something like this :
const https = require('node:https');
const fs = require('node:fs');
const httpsOptions = {
key : fs.readFileSync('path/to/server-key.pem'),
cert : fs.readFileSync('path/to/server-crt.pem')
};
const app = function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}
https.createServer(httpsOptions, app).listen(4433);
const options = {
key : fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
cert : fs.readFileSync('test/fixtures/keys/agent2-cert.pem'),
};
If you also want to support http requests, you need to make just this small modification :
const http = require('node:http');
const https = require('node:https');
const fs = require('node:fs');
const httpsOptions = {
key : fs.readFileSync('path/to/server-key.pem'),
cert : fs.readFileSync('path/to/server-crt.pem')
};
const app = function (req, res) {
res.writeHead(200);
res.end("hello world\n");
}
http.createServer(app).listen(8888);
https.createServer(httpsOptions, app).listen(4433);
2 Comments
createServer doesn't exist anymore? It's still documented in the Node.js v16.5.0 documentation in both nodejs.org/api/http.html & nodejs.org/api/https.html and not flagged as deprecated. Have you actually tried running this code? And, if so, which errors did you get?var https = require('https').Server(app); to var https = require('https'); Now, everything works... Thanks.Update
Use Let's Encrypt via Greenlock.js
Original Post
I noticed that none of these answers show that adding a Intermediate Root CA to the chain, here are some zero-config examples to play with to see that:
- https://github.com/solderjs/nodejs-ssl-example
- http://coolaj86.com/articles/how-to-create-a-csr-for-https-tls-ssl-rsa-pems/
- https://github.com/solderjs/nodejs-self-signed-certificate-example
Snippet:
var options = {
// this is the private key only
key: fs.readFileSync(path.join('certs', 'my-server.key.pem'))
// this must be the fullchain (cert + intermediates)
, cert: fs.readFileSync(path.join('certs', 'my-server.crt.pem'))
// this stuff is generally only for peer certificates
//, ca: [ fs.readFileSync(path.join('certs', 'my-root-ca.crt.pem'))]
//, requestCert: false
};
var server = https.createServer(options);
var app = require('./my-express-or-connect-app').create(server);
server.on('request', app);
server.listen(443, function () {
console.log("Listening on " + server.address().address + ":" + server.address().port);
});
var insecureServer = http.createServer();
server.listen(80, function () {
console.log("Listening on " + server.address().address + ":" + server.address().port);
});
This is one of those things that's often easier if you don't try to do it directly through connect or express, but let the native https module handle it and then use that to serve you connect / express app.
Also, if you use server.on('request', app) instead of passing the app when creating the server, it gives you the opportunity to pass the server instance to some initializer function that creates the connect / express app (if you want to do websockets over ssl on the same server, for example).
4 Comments
var https = require("https").server(app); And when I went to create server with https.createServer(...) I got the error message createServer not found. After changing the line to var https = require("https");, everything fell into place. Thank you...To enable your app to listen for both http and https on ports 80 and 443 respectively, do the following
Create an express app:
var express = require('express');
var app = express();
The app returned by express() is a JavaScript function. It can be be passed to Node’s HTTP servers as a callback to handle requests. This makes it easy to provide both HTTP and HTTPS versions of your app using the same code base.
You can do so as follows:
var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
var app = express();
var options = {
key: fs.readFileSync('/path/to/key.pem'),
cert: fs.readFileSync('/path/to/cert.pem')
};
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);
For complete detail see the doc
Comments
You can use also archive this with the Fastify framework:
const { readFileSync } = require('fs')
const Fastify = require('fastify')
const fastify = Fastify({
https: {
key: readFileSync('./test/asset/server.key'),
cert: readFileSync('./test/asset/server.cert')
},
logger: { level: 'debug' }
})
fastify.listen(8080)
(and run openssl req -nodes -new -x509 -keyout server.key -out server.cert to create the files if you need to write tests)
Comments
If you need it only locally for local development, I've created utility exactly for this task - https://github.com/pie6k/easy-https
import { createHttpsDevServer } from 'easy-https';
async function start() {
const server = await createHttpsDevServer(
async (req, res) => {
res.statusCode = 200;
res.write('ok');
res.end();
},
{
domain: 'my-app.dev',
port: 3000,
subdomains: ['test'], // will add support for test.my-app.dev
openBrowser: true,
},
);
}
start();
It:
- Will automatically add proper domain entries to /etc/hosts
- Will ask you for admin password only if needed on first run / domain change
- Will prepare https certificates for given domains
- Will trust those certificates on your local machine
- Will open the browser on start pointing to your local server https url