DEV Community

Cover image for Run your Node.js application on a headless Raspberry Pi

Run your Node.js application on a headless Raspberry Pi

Bogdan Covrig on February 17, 2019

Recently I've got a little piece of hardware (Raspberry Pi 2 Model B) on my desk. Rather than have it sit on its ass all day, I got a little Node.j...
Collapse
 
emh333 profile image
Ethan Hampton

This is great, thanks! Slightly off topic but do you have any experience with constantly running a Pi as a server 24/7 and any issues that might arise? I was thinking of doing something like this for my local network but was curious if there were any other things I might do to increase stability and lifespan. Again, thanks for the article!

Collapse
 
lundeee profile image
Lundeee

My Pi 2 is running for more than 3 years non stop. It is constantly measuring and saving enviromental data and serving simple page to check that data.

Collapse
 
dvddpl profile image
Davide de Paolis

this sounds similar to something i'd like to do. i'd like to use RasbPi + DHT11 Temperature and Humidity Sensor Module and send data to AWS Dynamo DB and then have a React APP displaying that info. could you please tell me more about your project?

Thread Thread
 
lundeee profile image
Lundeee

Hey. Goal of my project was just to level the thermostats on the first and second floor of the house. So i can be dad and yell "Don't touch the thermostat" :) I have DHT11 also and used Adafruit_DHT python module. Values are written to plain CSV and i used node.js and chart.js to display it. I use raspery for other thing now, but i left daemon running.

Collapse
 
bogdaaamn profile image
Bogdan Covrig

Since I started to write this article (one or two weeks back) I didn't unplug it at all. I actually started to test some of my real work on it (more robust APIs, databases, a lot of routes, automatic Postman tests) and never failed me. It uses an unnoticeable part of my home network bandwidth and almost no power at all, so comes in handy to have one around. Unfortunately, I don't know what sort of issues might arise if you use a lot of traffic and I did not monitor the stability. But I will keep you posted in case something goes wrong and maybe I will setup some benchmarking in the following days.

Collapse
 
bigorangemachine profile image
Brian Dinga

I made a CSS indexer. I used PhantomJS. There was some incidents of PhantomJS sub tasks not exiting which left some tasks hanging.

It depends on what you are doing. For the most part PM2 will cover what you need.

Collapse
 
chrisakers profile image
Chris Akers

Thanks for this, Bogdan. This was very easy to follow and clear. Although I ran into an issue that caused me to pull out my hair for several hours. I was following your example exactly. Everything was working well up to the point when I tried to make a request to the server from outside the Raspberry Pi. I went the ufw route and allowed port 3000. But my laptop on the same LAN could not get a response from the node server. (The same laptop was connected over SSH on port 22.) Running a port scan showed that only 22 was open. I tried many things including disabling/enabling ufw, rebooting, making ufw default allow, disabling ufw and setting iptables directly to the most permissive and simple set of allow rules, etc. Next on the hit list was the router. I went through all the router settings with a fine tooth comb. No help there.

I'm a web developer so I'm super comfortable with the node stuff, but the networking stuff is a bit out of my comfort zone. So I was sure that's where the problem was. There must be some firewall issue somewhere, right?

No. It turns out it was the node server all along. The example code passes the hostname to server.listen. So node is only responding to requests with that exact combination of hostname and port. Trying to hit it using a different hostname from outside the Pi failed every time. Once I changed to using the hostname-less listen method then it worked immediately and the port showed as open when running the port scan. The change:

server.listen(PORT, () => {
  console.log(`Server running on port ${PORT}.`);
});

It goes to show that sometimes the issue is where you least expect it. I hope this helps someone else if they run into this issue.

Collapse
 
bogdaaamn profile image
Bogdan Covrig

Great catch Chris! I spend some time taking a look to the documentation, see if I missed the parameters combination, but it seems indeed that it takes the exact combination of hostname and port.

Interesting to take a look at, I expected if you use the reverse proxy to get trough 127.0.0.1, right?

Collapse
 
chrisakers profile image
Chris Akers

Yes, I imagine that the reverse proxy would have worked properly since the hostname would match in that scenario. But I followed the "0. Don't use a Reverse Proxy :(" section since I was only making something for use in my LAN. The assertion at the end of that section is "Now you can access from the outside of the world! You can type your device's address followed by the port in your browser." This is not true since using the device's address will not match the hostname. :(

Thread Thread
 
bogdaaamn profile image
Bogdan Covrig

That's right, yeah. Thank you for the heads up, I've edited the code to a more general case

Collapse
 
dmitryvdovichencko profile image
Dmitry Vdovichenko πŸ’»πŸ€˜

Great article)) Thanks for this nice and useful tutorial)) I've mentioned that in the first step when I install NodeJS I should use

curl -sL https://deb.nodesource.com/setup_11.x | sudo bash -
Enter fullscreen mode Exit fullscreen mode

instead of

curl -sL https://deb.nodesource.com/setup_11.x | bash -
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kl7 profile image
KL

ditto

Collapse
 
dvddpl profile image
Davide de Paolis

this post is awesome. exactly what i needed to get started with RaspPi. I am planning a pet project with RaspPi (and humidity modules) and AWS stack to gather data and store it to DB and then have a React APP to display it from anywhere!
thanx

Collapse
 
bogdaaamn profile image
Bogdan Covrig

That's exactly the kind of cool things that you can do with a Pi! Keep me posted.

Collapse
 
mbariola profile image
Massimiliano Bariola

I install pm2 as instructed, but when I try to pm2 start app.js I get a pm2: command not found error. I see no errors during pm2 installation. I had to add

export PATH=$PATH:/opt/nodejs/lib/node_modules/pm2/bin
to my .bashrc
then source .bashrc

to make it work on npm 6.7.0 / 6.9.0, latest version of raspbian

Collapse
 
bogdaaamn profile image
Bogdan Covrig

Thanks for the heads up! Duly noted.

Collapse
 
ben profile image
Ben Halpern

This looks like a fabulous guide. Insta-bookmark.

Collapse
 
htalat profile image
Hassan Talat

Nice tutorial! What database can be setup on the pi?

Collapse
 
bogdaaamn profile image
Bogdan Covrig

You can setup any database that can be setup on Debian.

Collapse
 
htalat profile image
Hassan Talat

oh really? i was trying to setup mongodb on my pi3 once. Ran into some issues. will try again

Collapse
 
bushibot profile image
bushibot

I have hopefully easy question, I was following this to get node app to run background, but it requires a variable and the whole thing seems to fail when deomonizing it.
I'm trying to pass 'node resources/app/main.js --dataPath=$HOME/foundrydata' through PM2 but it seems to break.

Collapse
 
bogdaaamn profile image
Bogdan Covrig

yep, in order to pass node arguments to pm2 you have to use the --node-args argument. like

pm2 start resources/app/main.js --node-args="--dataPath=$HOME/foundrydata" 

Or you can add it in the pm2 JSON file. You can read more in the tutorial or in the pm2 docs.

Collapse
 
bassemibrahim profile image
Bassem

Great post! I am wondering tho can i then access this node server from outside the local network, i assume i will have to do some configuration on my router.

Collapse
 
bogdaaamn profile image
Bogdan Covrig • Edited

Haha, I was thinking the same a few days back. You should be aware that you might not be allowed since the traffic is monitored by your internet provider.

Oopsie, iliegal

This is the source for further reading. My provider states only The Customer is not permitted to rent the Service to a third party, to sell it or to make it available in any way, unless otherwise agreed. which might not be the case though.

But, yes, I assume that you have to setup a sort of domain name for your public IP or so.

Collapse
 
bassemibrahim profile image
Bassem

Will definitely investigate further, would be very cool to setup up stuff for personal use. Thanks, keep up the good work πŸ‘πŸ‘

Collapse
 
lfkwtz profile image
Michael Lefkowitz

Give ZeroTier a look, makes it very easy but still secure.

Collapse
 
paulc_creates profile image
Paul Caoile

Thank you for this. I will have to try this out since I have few RasPi waiting to be used for good. Do you have recommendations on ufw rules to make the connection more secure?

Collapse
 
bogdaaamn profile image
Bogdan Covrig

I would allow just the traffic from/to the ports that my API is using.

Collapse
 
paulc_creates profile image
Paul Caoile

Thank!

Collapse
 
ujjwalkr profile image
Ujjwal Kumar

btw do i really need the network cable if i have wireless connection??

Collapse
 
bogdaaamn profile image
Bogdan Covrig

No, my Pi didn't have wireless connection, therefore I used the cable

Collapse
 
bogdaaamn profile image
Bogdan Covrig

Thanks for the tip! Didn't have time before to check SystemD, since PM2 seemed the easiest out of the box way (that also uses SystemD), but will definitely check asap.

Collapse
 
danilloalvis profile image
Danilo Torquato

Great article, it helped me a lot, but I had a problem, I'm not able to upload files on node.js, on windows and MacOS I can upload files, but on raspberry not work

Collapse
 
dmcollins profile image
Danny McCollins

Great post, thank you very much!

Nginx isn't getting through UFW, I have to either disable UFW completely or allow port 80 which I think defeats the purpose of that section of your tutorial.