How to make express.js server run on http/2

Posted by Nishant on 16, Mar 2017

In the previous post I tried to do a comparision between HTTP/1.1 and HTTP/2, and based on that we set the premise that we should move to HTTP/2 for good.

With that settled, let's see how we can make express.js server run on HTTP/2.


We need to have SSL certificate and key with us in order to achieve aforementioned goal. For the purpose of this demo I will simply go with self signed cert and key generated via openssl using following command, but of course in the real world you will have to obtain that from a CA (i.e. certificate authority) someone like Let's Encrypt. Do check that out, it's free and pretty easy to setup.

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./example.key -out ./example.crt

Creating express.js server

We will use spdy as npm package which implements the http2, the other good choice is http2 npm package, however at the time of writting this, it has problems with express.js integration and does not work out of the box, so check the documentation if you decide to use it. Following are the only dependencies I am using for this demo.

+-- express@4.15.2
+-- spdy@3.4.4

following is how my directory structure looks like:

|-- package.json
|-- server.js
|-- sslcert
|-- |-- example.crt
|   |-- example.key
|-- www
    |-- sample.txt

and finally this is the content of server.js file:

const path = require('path');
const fs = require('fs');
const express = require('express');
const spdy = require('spdy');

const app = express();
app.use(express.static(path.join(__dirname, 'www')));

const options = {
    cert: fs.readFileSync(path.join(__dirname, 'sslcert', 'example.crt')),
    key: fs.readFileSync(path.join(__dirname, 'sslcert', 'example.key'))

//start http2 server, test url would be https://localhost:3033/sample.txt
spdy.createServer(options, app).listen(3033, () => {
    console.log('http2 server started on port', 3033);

//start http server, test url would be http://localhost:3000/sample.txt
app.listen(3000, () => {
    console.log('http server started on port', 3000);

In the above code we have setup express to serve static content from the www directory which has just one file sample.txt, actual content of the file does not matter. Although the demo only shows the static content being served from the express.js, the setup to run is on http2 is exactly the same for apis and server rendered pages.

Finally we have started the server in two flavors, one in simple http/1.1 mode on port 3000 and another on http2 mode on port 3033.

Verifying the outcome

Hit the url http://localhost:3000/sample.txt with chrome developer tool open and Network tab selected. You will see something like following:


Notice the protocol mentioned is http/1.1.

Note: you might have to enable the "protocol" column on the chrome chrome developers tool

Now again hit the url https://localhost:3033/sample.txt, you will see a chrome security warning, so bypass it using advanced option given in the page. This time you will see something like shown below in the chrome developers window.


Notice the protocol, it says h2.

That's it, we are running our express app on http2. That's how easy it is to migrate to http/2.