Setting up a Node.js server on a Raspberry Pi

  • Christopher Af Bjur
May 6th, 2021

You will learn how to setup a Node.js server on your Raspberry Pi which will always stay awake despite app crashes and RPI reboots. Note that this tutorial focuses on running the server on a local network but after finishing the steps, you'll be able to expose it publicly to the internet with ease with external guides attached at the end of this tutorial.

Installing Node.js

In this section we're going to install a fresh version of Node.js on our RPI by removing any previous versions and installing the latest LTS version using nvm (Node Version Manager).

Deleting previous installations

First of all we'll need to login to our Raspberry PI, either through the Raspberry Pi Desktop OS or by using SSH.

  • When you've accessed your RPI, open a terminal instance.
  • Update everything by running sudo apt-get update.

Terminal
sudo apt-get update

To obtain the latest versions of both Node.js and npm, we have to first remove and then reinstall their packages to ensure we obtain the latest releases. So run sudo apt remove node.

Terminal
sudo apt remove node

Now, let us proceed to the next step by running the following sudo apt remove nodejs.

Terminal
sudo apt remove nodejs

Note that we're removing both node and nodejs. Odds is that we have one of these packages installed on our RPI, so to be sure we remove node fully, we remove both of these; if they are installed they will be removed, if not, well we made sure they weren't.

Installing NVM

Run the following command. Note that there might be a later version of NVM at the time you read this. If you want to make sure you get the latest version, replace the command with that version. Check this link for latest version.

Terminal
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash

This script installs NVM and adds the correct paths and aliases to our environment. In order to get access to the nvm alias we'll have to update our terminal window. Easiest way is to just close it and open it again (if you're on a RPI Desktop OS). If you've SSH:ed in, just close your active terminal interface, open a new one and login to your RPI again.

Now run the following command to confirm that NVM was installed correctly:

Terminal
nvm --version

Installing Node.js

Let's install the LTS version of Node.js by running nvm install --lts.

Terminal
nvm install --lts

Run nvm ls to confirm which Node.js version we're using.

Terminal
nvm ls

Now also confirm that Node and NPM is installed correctly:

Terminal
node --version
npm --version

The output I get is node version v14.16.1 and NPM version 6.14.12 as of 2021-04-27.

Installing development tools

To be able to compile and install native add-ons from the npm registry you need to install the development tools.

Run sudo apt install build-essential. Note that when I ran this I got a message saying "build-essential is already the newest version (12.6)" and that some packages can be auto removed. I removed them by running the command sudo apt autoremove.

Terminal
sudo apt install build-essential

Installing VIM

In order to be able to copy/paste/edit code through a Terminal for our RPI files, we're going to install VIM.

  1. First run sudo apt-get update. Note that we recently ran this command so it's not really a necessity but it's something I've just "programmed" myself to do before I install any new packages.
  2. Then run sudo apt-get install vim -y

Terminal
sudo apt-get install vim -y

Creating the Node.js app

Now let's go to the root of our RPI by running:

Terminal
cd ~

Now that we're in the root let's create the app.js file and open it with VIM.

Terminal
vim app.js

Now copy/paste the following code:

Terminal
const http = require('http');

const PORT = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello from our RaspberryPI Server!\n');
});

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}.`);
});
  • Press the colon : key then type wq and press Enter to save this file and exit out of VIM.
  • Now we can confirm that app.js was created in our root by running ls.

Terminal
ls

Running the App

Now let's run the server file app.js that we just created by running the following command:

Terminal
node app.js

The server should print Server running on port 3000 in our terminal window.

Testing the App

Directly from our RPI

Open a new terminal window or tab on your RPI (since we're running the server in the previously opened tab). Note that if you've ssh'ed in you can just open a new terminal window or tab and login to your RPI from that terminal instance.

Then run curl localhost:3000 and we should get a message saying Hello from our RaspberryPI Server! from our running server.

Terminal
curl localhost:3000

From a computer on the local network

In a terminal of our RPI, type hostname -I in order to get the local ip address to our RPI. Copy it.

Terminal
hostname -I

Now open a web browser on your computer (connected to the same local network) and browse http://{your-local-rpi-ip-here}:3000/. We should now get a message saying Hello from our RaspberryPI Server! from our RPI server in our browser.

Keeping the server alive

We want the server to run in the background (so that we do not have to open new terminal tabs to navigate while the server has been started) and we want the server to automatically run when our RPI system is restarting. We can achieve this with PM2.

Installing PM2

  1. Let's stop our running server on our RPI by pressing Ctrl+C in the terminal window/tab where we started the server.
  2. Then in the same window/tab install PM2 by running npm install -g pm2

Terminal
npm install -g pm2

Running the server with PM2

With PM2 installed we can now start our server with PM2 by running:

Terminal
pm2 start app.js

You should see a table with id, name and pid i.e. This means the server is now running in the background and can be reached from http://{your-local-rpi-ip-here}:3000/ again as previously described.

Note that if the app crashes from now on, it will restart automatically.

PM2 Startup

Now it's time to setup PM2 on our RPI to automatically start when our RPI reboots.

First let's generate a script which we can use to configure this. Run the following command:

Terminal
pm2 startup systemd
  • Copy and run the generated command.
  • This created a system unit that will start PM2 on boot. When the system will boot, PM2 will resurrect from a dump file that we have not created yet.
  • To create the dump file run:

Terminal
pm2 save

This will save the current state of PM2 (with app.js running) in a dump file that will be used when resurrecting PM2.

PM2 Commands

  • We can run pm2 list in order to list all our currently running PM2 services.
  • pm2 show in order to show information about a running service. For instance we can type pm2 show app to show detailed information about the server we're currently running.

If you want to learn more about PM2 commands and how you can stop or delete a process, follow this link.

Extras

Copying existing app to RPI with SSH

If you're using SSH to connect to your RPI and want to copy an existing node project on your computer to it you can simply use the scp command.

Terminal
scp -r /path/to/local/dir pi@raspberrypi.local:/path/to/remote/dir
© 2021, Christopher Af Bjur