404

Given an SSL key and certificate, how does one create an HTTPS service?

John Slegers
  • 45,213
  • 22
  • 199
  • 169
murvinlai
  • 48,919
  • 52
  • 129
  • 177
  • 2
    without express and with the newest version of node - look here: http://stackoverflow.com/a/21809393/388026 – Philipp Kyeck Apr 09 '14 at 07:04
  • 2
    I used [restify.js](http://mcavage.github.com/node-restify/) 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 http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https/ – awaage Feb 28 '12 at 22:55
  • 1
    What happened to this question? The answers imply that it was originally about express.js. – doug65536 Oct 04 '15 at 04:42
  • it's trivial to create a valid, self-signed SSL cert and launch an HTTPS server, just a [few steps](https://github.com/75lb/local-web-server#https-server) – Lloyd Dec 09 '15 at 21:26
  • 4
    Its a bit late but if someone need a complete nodejs https tutorial, can find here: http://programmerblog.net/nodejs-https-server/ – Maz I Jun 10 '18 at 19:07
  • This could be helpful https://contextneutral.com/story/creating-an-https-server-with-nodejs-and-express – Nilesh Singh Feb 18 '19 at 23:25
  • This worked: https://stackoverflow.com/a/60947658/9585130 – Binh Ho Mar 31 '20 at 09:51
  • If you only want to test https://github.com/zoutepopcorn/localhapp – Johan Hoeksma May 14 '21 at 20:12

10 Answers10

528

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);
Cullub
  • 2,901
  • 3
  • 30
  • 47
Jacob Marble
  • 28,555
  • 22
  • 67
  • 78
  • 53
    Nice, was just about to post this myself. Thank you. Additionally, I found [this article](http://docs.nodejitsu.com/articles/HTTP/servers/how-to-create-a-HTTPS-server) helpful for generating a self-signed certificate. – clayzermk1 Jan 18 '13 at 00:13
  • 1
    Make sure you put `options` first in `https.createServer`, to avoid cryptic errors. – wberry Jul 26 '13 at 16:20
  • 1
    I am setting up an almost identical https server port 8888 and not sure how to change the routes. when I run curl curl --insecure https://localhost:8888 curl: (35) Unknown SSL protocol error in connection to localhost:8888 what is the error coming from and how to get around it. When I type localhost:8888 in the browser, it hangs and https:/localhost:8888 gives SSL error – reza Oct 25 '13 at 22:48
  • How do you force http connections through https? Can you do this through DNS, so that no one ever hits your website through plain http? – Costa Michailidis Apr 03 '14 at 14:29
  • 2
    @Costa you can redirect users from http to https with [express-force-ssl](https://github.com/battlejj/express-force-ssl) or hand written middleware - it [pretty straightforward](http://jaketrent.com/post/https-redirect-node-heroku/) – floatdrop Apr 06 '14 at 06:58
  • Thanks, @floatdrop! So, for security reasons I'm wondering if you can eliminate the http server completely. If someone has a cookie from my site, and they hit the http server, which redirects them to the https server, that makes them vulnerable, no? – Costa Michailidis Apr 07 '14 at 12:40
  • `cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')` should be changed to `cert: fs.readFileSync('test/fixtures/keys/agent2-cert.crt')` – user2720864 Apr 16 '15 at 11:57
  • Mine says bad password read, what do I do about the key password on the cert? – Nathan McKaskle Sep 06 '15 at 17:50
  • 1
    @NathanMcKaskle You can disable the password: Check this [guide](https://docs.nodejitsu.com/articles/HTTP/servers/how-to-create-a-HTTPS-server/) but if you are using macOS make sure that the generated key length is at least 2048: `openssl genrsa -out key.pem 2048` – sakisk Oct 17 '16 at 07:21
  • How about the case of using, var http = require('http').Server(app); rather than createServer. How could I use HTTPS then? – Benjamin Aug 23 '17 at 00:22
  • If I'm not wrong, this creates a server with SSL handshake. Does it also take care of encrypting the responses too? what symmetric encryption is used? Should it be taken care by the server before sending the responses? – ProgramCpp Sep 06 '17 at 06:15
  • You can also use [mkcert](https://mkcert.dev) to easily set up your SSL certificates – iono Aug 22 '22 at 17:37
  • Another good article about how to generate a self-signed certificate and set up a node server with it can be found [here](https://auth0.com/blog/using-https-in-your-development-environment/). – xEc May 04 '23 at 09:49
167

For Node 0.3.4 and above all the way up to the current LTS (v16 at the time of this edit), https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener has all the example code you need:

const https = require(`https`);
const fs = require(`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`)
};
Mike 'Pomax' Kamermans
  • 49,297
  • 16
  • 112
  • 153
hvgotcodes
  • 118,147
  • 33
  • 203
  • 236
  • 3
    `setSecure` is deprecated. Check this out instead http://stackoverflow.com/questions/5136353/node-js-https-secure-error – Larry Battle Oct 15 '12 at 21:05
  • 7
    See the official express answer below by @Jacob Marble. – clayzermk1 Jan 17 '13 at 23:53
  • 22
    This sample doesn't work anymore as the HTTPS implementation was re-done in Node.JS 0.4. See the corresponding docs at nodejs.org. http://stackoverflow.com/questions/5136353/node-js-https-secure-error?lq=1 – scottyab Apr 02 '13 at 10:46
  • posted an up-to-date (v0.10.x) answer [below](http://stackoverflow.com/a/21809393/388026) – Philipp Kyeck Feb 16 '14 at 09:23
  • 12
    This answer is very old and does not work anymore. Please see the answer by pkyeck below, or go to: http://nodejs.org/api/https.html – Jay Sheth Apr 08 '14 at 19:16
  • 2
    Also the link is broken – TlonXP Nov 10 '14 at 16:45
  • I know your answer was right but it does not work on my Mac, until I found this article: https://engineering.circle.com/https-authorized-certs-with-node-js-315e548354a2#.abtx7zq78 . – BollMose Sep 19 '16 at 03:58
  • I had some issues whyle setting up OpenSSL certificate on my Subsystem Linux Windows, for running SSL on localhost for node.js / secure sockets, long story short, I tired out 3-5 "recepies" and the simplest and shortest one was here (10 minutes and it worked out, against 1 day of unlucky tries): https://flaviocopes.com/express-https-self-signed-certificate/ (yes it is for Mac but it worked for my Ubuntu 20 ) – Yarik Jan 29 '22 at 15:18
90

Found this question while googling "node https" but the example in the accepted answer is very old - taken from the docs of the current (v0.10) version of node, it should look like this:

var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(8000);
Community
  • 1
  • 1
Philipp Kyeck
  • 18,402
  • 15
  • 86
  • 123
  • Worked like a charm. This information came in very handy as I run a node.js tool (PDFJS) on top of a PHP app that was recently forced to run over https. The iframe was very unhappy to load my node.js app on an alternate, non-https port. – lewsid Oct 07 '14 at 16:12
  • 2
    This looks good, but how can I generate the files you are requiring there (`*.pem`)? I tried [following this page](https://freenode.net/certfp/makecert.shtml), but when opening `localhost:8000` in the browser, no data is received (just loading...). – Ionică Bizău Feb 22 '15 at 20:03
  • 8
    @IonicăBizău, for generating keys, install `openssl`, then in cmd prompt, type `openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3001` – mido Apr 06 '15 at 03:08
  • 2
    @IonicăBizău you need to directly go to `https://localhost:8080`. HTTP is NOT HTTPS. – Florian Wendelborn Aug 20 '15 at 14:52
  • Is it possible to create https-server with folder? So you can put file in it and access that file like https://localhost:81/main.js – FrenkyB Nov 20 '19 at 01:43
  • @FrenkyB there is https://github.com/cloudhead/node-static that can help you with that – Philipp Kyeck Nov 20 '19 at 09:15
49

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});
Jacob Marble
  • 28,555
  • 22
  • 67
  • 78
nu1silva
  • 595
  • 4
  • 2
23

The minimal setup for an HTTPS server in Node.js would be something like this :

var https = require('https');
var fs = require('fs');

var httpsOptions = {
    key: fs.readFileSync('path/to/server-key.pem'),
    cert: fs.readFileSync('path/to/server-crt.pem')
};

var app = function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}

https.createServer(httpsOptions, app).listen(4433);

If you also want to support http requests, you need to make just this small modification :

var http = require('http');
var https = require('https');
var fs = require('fs');

var httpsOptions = {
    key: fs.readFileSync('path/to/server-key.pem'),
    cert: fs.readFileSync('path/to/server-crt.pem')
};

var app = function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}

http.createServer(app).listen(8888);
https.createServer(httpsOptions, app).listen(4433);
John Slegers
  • 45,213
  • 22
  • 199
  • 169
  • 2
    All these answers are OLD and OUTDATED. I wish StackOverflow would cleanup up questions and answers that are VERY VERY OLD. `createServer` DEPRECATED! This function DOESN'T exists anymore. – ThN Jul 21 '21 at 15:51
  • What are you talking about? What do you mean `createServer` doesn't exist anymore? It's still documented in the Node.js v16.5.0 documentation in both https://nodejs.org/api/http.html & https://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? – John Slegers Jul 23 '21 at 08:13
  • 1
    actually I figured out my mistake. There was one line that needed changed `var https = require('https').Server(app);` to `var https = require('https');` Now, everything works... Thanks. – ThN Jul 23 '21 at 15:06
18

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:

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).

coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • This is a nice explanation but, the provided link in the update section, is broken (gives 500 error) – Chucky Oct 22 '19 at 20:36
  • 1
    All these answers are OLD and OUTDATED. I wish StackOverflow would cleanup up questions and answers that are VERY VERY OLD. – ThN Jul 21 '21 at 15:50
  • @ThN What isn't working for you? What's a newer, better solution? – coolaj86 Jul 21 '21 at 17:30
  • 1
    @coolaj86 After long time of trial and turbulence (lol), I have figured out my issue. It works now. I had a line `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... – ThN Jul 21 '21 at 19:20
10

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

cmd
  • 11,622
  • 7
  • 51
  • 61
1

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)

Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73
0

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
Adam Pietrasiak
  • 12,773
  • 9
  • 78
  • 91
-4
  1. Download rar file for openssl set up from here: https://indy.fulgan.com/SSL/openssl-0.9.8r-i386-win32-rev2.zip
  2. Just copy your folder in c drive.
  3. Create openssl.cnf file and download their content from : http://web.mit.edu/crypto/openssl.cnf openssl.cnf can be put any where but path shoud be correct when we give in command prompt.
  4. Open command propmt and set openssl.cnf path C:\set OPENSSL_CONF=d:/openssl.cnf 5.Run this in cmd : C:\openssl-0.9.8r-i386-win32-rev2>openssl.exe
  5. Then Run OpenSSL> genrsa -des3 -out server.enc.key 1024
  6. Then it will ask for pass phrases : enter 4 to 11 character as your password for certificate
  7. Then run this Openssl>req -new -key server.enc.key -out server.csr
  8. Then it will ask for some details like country code state name etc. fill it freely. 10 . Then Run Openssl > rsa -in server.enc.key -out server.key
  9. Run this OpenSSL> x509 -req -days 365 -in server.csr -signkey server.key -out server.crt then use previous code that are on stack overflow Thanks
  • 2
    this is [OT](https://meta.stackexchange.com/questions/40353/stack-exchange-glossary-dictionary-of-commonly-used-terms). The OP's question is clear. Certificates are already given. – Martin Schneider Jul 27 '17 at 08:38