In this tutorial we will check how to setup a HTTP/2 server on the Raspberry pi 3, using Node.js. This tutorial was tested on a Raspberry Pi 3 model B+ running version 4.9 of Raspbian.
Introduction
In this tutorial we will check how to setup a HTTP/2 server on the Raspberry pi 3, using Node.js.
It’s important to take in consideration that you might need to update your Node.js version to have access to the HTTP/2 module. You can check this guide on how to update the Node.js version on the Raspberry Pi.
Currently no browser supports HTTP/2 without encryption [1], which means our server will need to be able to operate with a secure connection (HTTPS).
Consequently, we will need to generate a server certificate and a private key for testing. The certificate will be a self signed, since we are just going to use it locally. The procedure to generate the files is explained in more detail on the next section.
This tutorial was tested on a Raspberry Pi 3 model B+ running version 4.9 of Raspbian. The Node.js version used was 12.2.0.
Generating the certificates
As mentioned in the introductory section, we will need to generate a server certificate and a private key. For that, we will use openssl.
At the time of writing, version 4.9 of Raspbian comes with openssl already installed, so we can just run the following command to generate the files:
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -subj '/CN=localhost' -keyout localhost-privkey.pem -out localhost-cert.pem
Note that the previous command is indicated in the Node.js HTTP/2 module documentation, as can be seen here.
So, after sending the command, you should get an output similar to figure 1.
Figure 1 – Generating the server certificate and private key with openssl, on the Raspberry Pi.
Upon running this command, you should get two files on the directory where the command line is located:
localhost-cert.pem
localhost-privkey.pem
In case you are having troubles generating the files, below are examples that you can use to test the server:
localhost-cert.pem
-----BEGIN CERTIFICATE-----
MIIC/jCCAeagAwIBAgIJAKrxXBzX+HgWMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0xOTA1MTUxODQ3NDBaFw0xOTA2MTQxODQ3NDBaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKESwQlGqm/XcabGehan+L+Ev5ObRsM/AuS0LVrURFk50fylWay6Pb1yQ0Dd
wUI/f8oxoxuaFf7jVVSyA+HLJYz6WM5TZIN2sy6LwT8o8ALUwU9vSxP1UvNo0B1m
9YBul+cnhXEu1c2YgNC7ImnkAjX0ZrhnkLNRfDzcQp1rJG8fmmqaetnDZ3YYLO4M
SXLHFS3PmJzke7ultbN519VxEC1abJ1rtEAfTDb4AjyV0swfxO2ts9bCCju/CIL4
tEshlWwr24xJhuYLPnVEXxUAC4bW8zxSrkBfB94nZjHeqzZXgzjVI4xbC/jspr7B
T0IVOSh5RSWT0zdN6npxPvuxPm0CAwEAAaNTMFEwHQYDVR0OBBYEFOEtoSOKdcgl
pV22O8wXX8IIscKNMB8GA1UdIwQYMBaAFOEtoSOKdcglpV22O8wXX8IIscKNMA8G
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABrO6JSwbI7jwfzrlS6K
AecFd5tBdmnxesf/67puLJICjiVgi0qP2f15oQVSrlRXNCJ7smmTT6VBfuNszi0s
+82F+vcCrll/q+tsGEUE6ZQQCMHBNfe59outr44nTDAGwpwTtGSl0UhCqf7qyWPY
go+OMZsv6bIb4ch7Nav6fyX5t6Z/WsEOnZZRYiSpD1qHpeSXLrab2j/NvvyUvcHl
Eg6Mxm7DhFinIceYoQ/XWm3RSPBKu4faIty5+fU6cxhXRpLHI2KP5tCdZyymDiBd
J4LYp0zoHHb/+adscorA/fZEd/z3aICncYxBSuI9rR2fzBwyJ84XvlrSTxfUN7+l
Roo=
-----END CERTIFICATE-----
localhost-privkey.pem
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQChEsEJRqpv13Gm
xnoWp/i/hL+Tm0bDPwLktC1a1ERZOdH8pVmsuj29ckNA3cFCP3/KMaMbmhX+41VU
sgPhyyWM+ljOU2SDdrMui8E/KPAC1MFPb0sT9VLzaNAdZvWAbpfnJ4VxLtXNmIDQ
uyJp5AI19Ga4Z5CzUXw83EKdayRvH5pqmnrZw2d2GCzuDElyxxUtz5ic5Hu7pbWz
edfVcRAtWmyda7RAH0w2+AI8ldLMH8TtrbPWwgo7vwiC+LRLIZVsK9uMSYbmCz51
RF8VAAuG1vM8Uq5AXwfeJ2Yx3qs2V4M41SOMWwv47Ka+wU9CFTkoeUUlk9M3Tep6
cT77sT5tAgMBAAECggEBAIi27FW9PyjSysptqG7Wf5G/UQQuRa+vKfuI2v4/MQwy
wYMZrbWoFoNYGrFSB5j9YK/z1ae173l655CN0DG0RdkVHI9zxNq4w3l8cbf0PVOJ
1dJgem8kSRYFHq/2Fea+9/vhVagtwpdRG/UPATSzrRSyrwVSEkXBohveMESBDlmq
NpLZlP3VgscHIjYragU2c77uRCk8pc1BLOWStj9qH7HHIwPEDlyWBvniu9d4bSP1
AlP4S779Odm8qixwHMGofFK4QoNcjkLIog4aC/vsoEpxG2QgFNkdGfz1asHZoEqW
EZzbbZQ4vIny+lyAvS8ucekaLtwiusG1xZOCIurRPkECgYEAz1KgMXMQP4Wif2Yw
lEMIdn0DcN4kyekT+DBHV+I4MZKmGMCxJeHiKe1SjTNLPkEG2th5N/julusN9SFi
0iZiO3i3G30n7IW2siQoy25lRUYioHp1ezVeZhaJqUmg4CZ/YoAuFVb9fQ52Ppb9
QAM6qoYuKp/dENHGQS7/6GMaT2UCgYEAxuQ/prn/J0F1S3Y3GxpoJAu3wOE71CCl
JsnExpxzg7GQavha7ogwuoAEgvPJ7bQ0ArfjfwuYOdbEz2lOfTW9/T1MuWDlySyU
VIte4ztHgHqhR8CfuB0ZMXffYm6YX1MBrzfs2++fcHlX8sQFzrk6HIoHw9DqR/Vm
fgA3keeEFmkCgYAmYp/yR+GMQUvS1rLL4JViisbmUNry30qpOxcaeHH7C7HhB1xF
LUtYg+4y4npd7mA8iLP43wgdvSt6ZVIMorqxVCpi1otbyW4IEZXUBH6Pkuq6V7IE
u97ce/PE+jLlDXusWxstLEwGqXTPJdmBzpdAF1PY5HxjrtNMIk2TUzX92QKBgAWw
tA1+Fsm1urhc+nihCce2OhyflQmdoXv5m9Ke2UM0SlB1KIzYgqRjUz234dgWJsLJ
Jg4Vc9Z7yYexmJhGeFgNb+uB1TErQFcm4aEYqhQH7iNSZH9s/bKHnnF/foaDpnGv
5Ovp8CLUpeqBJzVh4UK9xDka+gjzAWqrcOuQtxu5AoGALAa4HNasYdUmZtDGWZcs
CSA2i9W8BYuhnyQI3Su1pDtycIQVCpyXP6XBGcGG/lh/OK2Z4AjY4LCaSfXADn2S
clIOKjm01YTbbEyImYmOzJEYiax3nQ23EtqxeOOGQ4KWom/gCEIdMNYHtD91bYLj
coM3G3ZXJ1Vdkm4HJTXh2Ho=
-----END PRIVATE KEY-----
In case you use the previous examples, don’t forget to use the correct file names and extensions.
Once you have both files, create a folder in a location of your choice. Then, place both the server certificate an key files on that folder.
After this, create a new file called “testHttp2.js“. This will be the file where we will write the code to run the server. The next section details all the code we need.
Figure 2 illustrates how the content of the folder should look like.
The code
We will start our code by including the modules we require to setup the HTTP/2 server. We will need the HTTP/2 module, which will expose the functionalities needed to setup the server.
const http2 = require(
'http2'
);
We will also need to import the file system module, so later we are able to read the content of the certificate and private key files.
const fs = require(
'fs'
);
Moving on to the next part of our code, now we need to define a callback function that will be executed whenever a HTTP/2 is received by the server.
This callback function will be invoked with two arguments:
An object of class Http2ServerRequest, which can be used to access the request status, headers, and data;
An object of class Http2ServerResponse, which allow to send data back to the client.
We will call this function onRequest and, as already mentioned, its signature will have two parameters:
function onRequest (req, resp) {
// Implementation of the callback function
}
The implementation of the function will simply consist on returning an “hello world” message back to the client. We can do this by calling the end method on our Http2ServerResponse object and passing as input the string we want to return to the client.
Additionally to send the data back to the client, this method call will signal to the server that the message was completed.
function onRequest (req, resp) {
resp.end("Hello World");
}
After this we need to create our HTTP/2 server. This is done with a call to the createSecureServer function from the HTTP/2 module.
As first input of this method, we will pass an object containing the server key and certificate. This object should have a field called key, with the content of our private key file, and a field called cert, with the content of our certificate.
To get the content of these files we can simply use the readFileSync function of the File System module. As input of this function, we just need to pass the path to the files.
Since the files are located in the same folder where we have the Node.js script, we simply need to use the file names.
Going back to the createSecureServer function, it receives as second parameter a callback function that will be executed when a request is received. Naturally, we should pass our previously defined onRequest function.
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
}, onRequest);
To finalize, we need to call the listen method on our server object, passing as input the number of the port where it will be listening for incoming requests. For testing, we will be using port 8443.
server.listen(8443);
The final code can be seen below.
const http2 = require('http2');
const fs = require('fs');
function onRequest (req, resp) {
resp.end("Hello World");
}
const server = http2.createSecureServer({
key: fs.readFileSync('localhost-privkey.pem'),
cert: fs.readFileSync('localhost-cert.pem')
}, onRequest);
server.listen(8443);
Testing the code
To test the code, we first need to run the previous Node.js script. You can check in detail how to run a Node.js script on the Raspberry Pi on this previous tutorial.
So, to execute the script, simply open a command line and navigate to the folder where the script is located. Then, run the following command:
Figure 3 illustrates the previous command, sent on the Raspberry Pi command line.
After running the script, open the Raspberry Pi web browser. Then, type the following URL in the browser address bar and click enter:
https://localhost:8443/stream
Note that we are using an endpoint called “stream” but we could use any other endpoint instead, since our server implementation will always return an answer back to the client.
After navigating to the URL, if the browser warns about some security issues, choose to advance. This happens because we are using a self signed certificate, which was not issued by any authority that the browser knows. Consequently, the browser will mark it as insecure. Naturally, for a real scenario application, you should not use a self signed certificate.
At the end, you should get a result similar to figure 4. As can be seen, the “Hello World” message we defined on the code is returned to the browser, as expected.
Figure 4 – “Hello World” message returned to the browser.
References