How to Run NodeJS on a Headless Raspberry Pi

raspberry-pi-4-and-zero-w-500-2.jpg

This article covers how to run NodeJS on a headless Raspberry Pi or Pi Zero W. It also covers how to autostart your site after a reboot or crash using pm2 and manage source files with git.

I'll walk you through the steps for:

  • Installing NodeJS on a Pi to run Web apps
  • Installing git and using it to clone a sample app
  • Installing pm2 to keep your NodeJS apps running after restarts or crashes

Step 1. Use a lite Raspbian image

To test the steps in this article, I used Raspbian Buster Lite. If you need to install a lite version, I've written a couple of posts on how to do that:

Note that if you are using the full version of the Pi desktop, you may have some version of node installed already. These instructions were only tested on the lite version.

You can tell if you have NodeJS already installed by remote logging into the Pi or opening up a terminal window and running this command:

node -v

If you didn't get an error, then you can skip down to the part about installing git.

Step 2. Get the ARM version

Before you install NodeJS, you first have to determine what type of architecture your Pi is using.

Remote login to the Pi and run this command.

uname -a

Look for a string in the results that starts with armv (armv7l, armv6l, etc).

Here is an example from my Raspberry Pi 4:

Linux pi4 4.19.50-v7l+ #895 SMP Thu Jun 20 16:03:42 BST 2019 armv7l GNU/Linux

Notice the second to last string is armv7l ? That tells me I will need to download the NodeJS build that was compiled for armv71.

Step 3. Install for your ARM version

This step contains multiple sets of instructions. Use the steps that match your device and/or ARM version,


Raspberry Pi 4 (armv7l)

Raspberry Pi 3 B+ (armv7l)

Here are the instructions to install NodeJS for a Raspberry 3 B+ or a Raspberry 4. You will need to install the armv7l version. If you want to install for a Pi Zero W skip down to those instructions below.

The 3 B+ and the 4 can run NodeJS v12. To see the latest version of v12, browse to:

At the time of this writing, the latest version was v12.6.0. If the version has since changed, adjust the URLs below accordingly:

From your host computer remote login to the Pi over ssh (replacing YOUR-PI with your pi's hostname):

ssh pi@YOUR-PI.local

Get the latest version (browse the link above to see if the latest version has changed):

wget https://nodejs.org/dist/latest-v12.x/node-v12.6.0-linux-armv7l.tar.gz

Extract the files:

tar -xzf node-v12.6.0-linux-armv7l.tar.gz

Copy to /usr/local:

sudo cp -R node-v12.6.0-linux-armv7l/* /usr/local/

The next set of instructions are for the Pi Zero W. If you don't need to install for that device, then you can skip down to the next step.


Pi Zero W (armv61)

If you are using a Pi Zero W based on armv6l then you will need to use an older version of NodeJS. There is currently no support for that in v12.

These instructions are for the last supported armv61 version: v11.15.0.

You can confirm that your Pi Zero W is using armv61 by running:

uname -a

Get the last supported version that supports the Raspberry Pi Zero W:

wget https://nodejs.org/dist/v11.15.0/node-v11.15.0-linux-armv6l.tar.gz

Extract the files:

tar -xzf node-v11.15.0-linux-armv6l.tar.gz

Copy to /usr/local:

sudo cp -R node-v11.15.0-linux-armv6l/* /usr/local/

Step 4. Check the NodeJS version

To check that NodeJS is installed and working, run this command:

node -v

You should see a version number that matches what you downloaded.

Step 5. Cleanup

The installation steps downloaded a binary and created a temporary folder in the home directory. Those are no longer needed and it is safe to delete them by running this command:

rm -rf node-v*

Step 6. Install git

I never edit source files on a Pi directly. In some cases I will use something like scp or rsync to move files to and from my Pi. But my preferred method is to post files to a git repo. Then use the git client to pull them down to the Pi.

To install git on the Pi:

sudo apt install git

Step 7. Clone and run the sample app

I've a posted very simple NodeJS Hello World app to GitHub. You can use it to verify that your NodeJS install is working.

To clone and run my app:

git clone https://github.com/mitchallen/nodejs-hello-world.git
cd nodejs-hello-world/
npm start

You should see:

Listening on port: 3000

On another computer browse to:

Substitute YOUR-PI with your Pi hostname or replace 'YOUR-PI.local' with your Pi's ip address.

Once you've confirmed it's working, back on the Pi, press Ctrl-C to stop the server from running.

Step 8. Install pm2

If NodeJS crashes or your Pi restarts, you currently have to login again and restart it. To solve that problem I'm going to show you how to setup pm2 to keep your NodeJS app running, even if it crashes or restarts.

sudo npm install -g pm2

Don't worry if you see skipping optional dependency messages.

Step 9. Run pm2

When you run pm2 for the first time it needs to initialize.

Run the command to display a status report:

pm2 status

Because pm2 needs to start first, you will see a logo, some instructions and a message like this:

[PM2] Spawning PM2 daemon with pm2_home=/home/pi/.pm2
[PM2] PM2 Successfully daemonized

Followed by a status report.

If you run that command again, now that pm2 is running, you will just see the status report.

Step 10. Run the app under pm2

You can run a NodeJS app, Python app or even a bash script under pm2. It will monitor your app or script to make sure it is running. If the app unexpectedly stops, pm2 will attempt to restart it.

cd ~/nodejs-hello-world/
pm2 start hello.js

The start command will also trigger the status command, where you should see that your app (hello) is running.

Step 11. Save and resurrect apps

If you reboot your Pi, the services you setup will be lost. You can at least save them with this command:

pm2 save

If you do reboot, you can restart saved pm2 apps by using this command:

pm2 resurrect

Step 12. Run on startup

After a reboot, you don't want to have to remote login to the server and restart apps all the time. Fortunately you can setup a service to startup pm2 when the Pi is rebooted. Behind the scenes on startup the pm2 service will resurrect anything saved.

To setup pm2 to automatically start when your Pi reboots, run this command:

pm2 startup

You will see output with instructions. You still have to follow the instructions to make pm2 start automatically on reboot:

[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi

Copy the last command line to the clipboard, then run it:

sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u pi --hp /home/pi

To test it, reboot the Pi with this command:

sudo reboot

At this point you don't need to login again. The pm2 service should have been started, resurrecting any pm2 process that you have saved.

To prove it is working, wait a minute and then browse to (substituting YOUR-PI):

http://YOUR-PI.local:3000

Step 13. Login again to check the service

Remote login to the Pi again after it rebooted using ssh. Then check the pm2 status:

pm2 status

You should see that pm2 and your NodeJS app are already running.

A this point, you can press Ctrl-D to logout and leave the server running.


pm2 tips and tricks

Below you will find some additional tips and tricks for working with pm2.

Test crash handling

To test how pm2 handles your app crashing, use pfkill to kill the app:

pkill -f node
pm2 status

Notice that the restart count has incremented by one. That's pm2 doing it's job. If your app crashes, pm2 will attempt to restart it.

Restart all

To restart all services managed by pm2, run this command:

pm2 restart all

This will restart your app and show the status. You should notice that the app restart count has again incremented.

pm2 logging

Assuming the id of hello in the status grid came up as 0 (zero), pass that id to the pm2 log command:

pm2 log 0

Because the app was started and restarted multiple times by pm2, you should see multiple listening messages in the log. They were generated every time the hello app was started:

0|hello    | Listening on port: 3000
0|hello    | Listening on port: 3000
0|hello    | Listening on port: 3000

Removing an app from pm2

To stop pm2 from resurrecting an app you can use the delete command. It will only delete the app from pm2's list of apps to restart. It won't delete the app itself:

pm2 delete 0

I've provided links in the references below to the official pm2 documentation.

References



About the Author

Mitch Allen works for a robotics company in New England.