Install Node.js and Npm on Raspberry Pi

Step 1: Detect What Version of Node.js You Need

The processor on Raspberry Pi is ARM, but depends on the model there can be ARMv6, ARMv7 or ARMv8. This 3 versions of ARM is supported by Node.js.

So first of all type this in your terminal on raspberry pi to detect the version that you need:

uname -m

If the response starts with armv6 than that’s the version that you will need. For example for raspberry pi zero W you will need ARMv6

Step 2: Download Node.JS Linux Binaries for ARM

Go to node.js download page and check right click on the version of ARM that you need and choose Copy Link address.

After that in the terminal using wget download the tar.gz file for that version. Just type wget, paste the link copied before and make sure the extension is .tar.gz. If it’s something else change it to this and it should be ok. For example I will need ARMv6 and I will type this in my terminal:

cd ~
wget https://nodejs.org/dist/v14.15.0/node-v14.15.0-linux-arm64.tar.xz

Step 3: Extract the Archive

Using tar that is already installed with the system on your raspberry pi just type this (make sure you change the filename with the file that you have)

tar -xf node-v14.15.0-linux-arm64.tar.xz

Step 4: Copy Node to /usr/local

cd node-v14.15.0-linux-arm64
sudo cp -R * /usr/local/

Step 5: Check If Everything Is Installed Ok

node -v
npm -v
# Delete unused
cd ~
rm node-v14.15.0-linux-arm64.tar.xz
rm -rf node-v14.15.0-linux-arm64

Now you have node.js installed on your Raspberry Pi and working so you can build something using node.

NPM là gì? Sử dụng NPM hiệu quả để đơn giản hóa công việc

NPM là gì?

NPM là gì? – NMP là viết tắt của Node package manager là một công cụ tạo và quản lý các thư viện lập trình Javascript cho Node.js. Trong cộng đồng Javascript, các lập trình viên chia sẻ hàng trăm nghìn các thư viện với các đoạn code đã thực hiện sẵn một chức năng nào đó. Nó giúp cho các dự án mới tránh phải viết lại các thành phần cơ bản, các thư viện lập trình hay thậm chí cả các framework.

Công dụng của NPM là gì

Với npm , công việc sẽ đơn giản đi rất nhiều, chúng giúp bạn thực hiện việc quản lý đơn giản hơn rất nhiều. Các thư viện đều có sẵn trên npm, bạn chạy một dòng lệnh để tải về và dễ dàng include chúng hơn.

Mỗi đoạn code này có thể phụ thuộc vào rất nhiều các mã nguồn mở khác, thật may mắn khi các công cụ quản lý thư viện ra đời, nếu không sẽ mất rất nhiều công sức trong việc quản lý các thư viện này.

Cộng đồng sử dụng npm rất lớn, hàng nghìn các thư viện được phát hành, hỗ trợ Javascript ES6, React, Express, Grunt, Duo… Hiện nay cũng đã xuất hiện thêm Yarn một công cụ tương tự npm, được Facebook phát triển với nhiều tính năng vượt trội có khả năng sẽ thay thế npm.

Nếu như bạn từng code Php thì sẽ biết Composer là công cụ quản lý thư viện của nó, tương tự như NPM là công cụ quản lý thư viện Javascript.

Cài đặt NPM

npm có sẵn khi bạn tải NodeJS về. Để kiểm tra xem trên hệ thống của bạn đã được cài npm chưa chúng ta sử dụng lệnh npm -v, nếu một phiên bản hiện ra thì hệ thống của bạn đã được cài đặt npm.

Vì NPM là một phần mềm cài đặt trên máy tính của bạn nên bạn có thể sử dụng nó để cài đặt các thư viện Javascript từ trên Internet. Để cài đặt một thư viện nào đó, chỉ cần mở cửa sổ Terminal (hoặc CMD) và thực thi lệnh giống dưới đây:

npm install package-name

VD như mình thử tải Vuejs về sử dụng sẽ dùng lệnh:

npm install vue

Khi đó muốn sử dụng Vue.js chúng ta chỉ cần sử dụng lệnh require():

var Vue = require('vue');

Cài đặt global và cài đặt local

Có hai cách để cài đặt một gói bằng npm:

  • Local: sẽ tạo ra thư mục node_modules nếu chưa có trong project hoặc nếu có rồi nó sẽ lấy code của gói cần cài đặt đưa vào đây, tức chỉ hiện diện trong thư mục của project hiện tại. Khi cần sử dụng bạn có thể sử dụng lệnh require().
  • Global: sẽ lưu trữ code của gói trong các file hệ thống cố định trong máy, chỉ có thể dùng các package này thông qua các hàm CLI (Command Line Interface) ví dụ như gulp. Không thể dùng package thông qua require().

Mặc định thì các package khi cài đặt đều sẽ là cài trên project của bạn.

npm uninstall package_name

Các package thư viện đưa vào project của bạn có thể liên tục có update mới. Thực hiện npm update để thực hiện cập nhật tất cả các gói liên quan. Nếu bạn chỉ muốn cập nhật một gói cụ thể có thể sử dụng cú pháp:

npm update package_name

Các câu lệnh này có thể sử dụng flag -g để thực hiện cập nhật cho các gói được cài đặt global.

Kiểm tra các gói cài đặt

Để kiểm tra các gói đã được cài đặt thông qua npm sử dụng câu lệnh npm ls, nếu kiểm tra các cài đặt global thêm tham số -g

npm ls
npm ls -g

Package.json

Trong các project Node.js chuẩn đều chứa file package.json nhưng bạn có biết nó dùng để làm gì?

File package.json là gì?

File package.json được dùng để thực hiện các việc sau:

  • Chỉ rõ phiên bản của project và mô tả project (tên project, tác giả, bản quyền…)
  • Liệt kê các packages mà project phụ thuộc (các thư viện mà project sử dụng)
  • Dễ dàng chia sẻ project giữa các developers, giúp project có thể được sử dụng lại như một thư viện.

Các trường trong file package.json

Một file package.json bắt buộc phải có 2 trường "name" và "version"

  • "name": tên của package / project, phải là chữ cái thường (lowercase) và chỉ gồm một từ, có thể bao gồm ký tự gạch ngang / gạch dưới.
  • "version": phiên bản của package /project. Phải có định dạng x.x.x và tuân theo semantic versioning guidelines.

Một số trường khác:

  • "description": mô tả project
  • "main": file main được chạy.
  • "script": định nghĩa các script.
  • "author": tác giả project
  • "license": bản quyền project
  • "dependencies": các thư viện sử dụng

Ví dụ: package.json

{
"name": "nodejs-demo",
"version": "1.0.0",
"description": "node.js hello",
"main": "index.js",
"scripts": {
"test": "node test.js"
},
"keywords": [],
"author": "stackjava.com",
"license": "ISC",
"dependencies": {
"string": "^3.3.3"
}
}

Phần script, khi mình chạy lệnh test là node test.js nên khi chạy lệnh npm test thì nó sẽ chạy lệnh node test.js

Phần dependencies, mình khai báo "string": "^3.3.3" thì khi cài đặt (npm install) thì nó sẽ cài thư viện string với version >= 3.3.3

Cách tạo file package.json

Cách 1: bạn tạo file text với tên package.json và nhập bằng tay các giá trị với cấu trúc như ở trên.

Cách 2: dùng lệnh npm init

npm init

Ví dụ mình muốn tạo một project node.js ở folder C:\Users\stackjava\Desktop\demo thì mình sẽ mở màn hình cmd/powershell và di chuyển tới folder đó:

cd C:\Users\stackjava\Desktop\demo

Sau đó chạy lệnh npm init và nhập các các thông tin:

Kết quả là file package.json được sinh ra với các thông tin đã nhập ở trên:

{
"name": "demo",
"version": "1.0.0",
"description": "nodejs hello",
"main": "index.js",
"scripts": {
"test": "node test.js"
},
"author": "stackjava",
"license": "ISC"
}

Bạn cũng có thể tạo file package.json mặc định bằng lệnh npm init -y nó sẽ tạo một file package.json với các thông tin mặc đinh.

Ví dụ:

Trong ứng dụng bạn nên soạn trước package.json giữ lại nó cùng với các files mã nguồn. Không cần thiết giữ lại các packages và modules Khi cần thiết lập lại ứng dụng ở 1 nơi khác. chỉ việc vào thư mục chứa pakage.json và dùng lệnh nmp install không có thông số, nmp sẽ tự động download về các gói đã chỉ định sẳn trong pakage.json

ví dụ: pakage.json

{
  "name": "daihuudsf",
  "version": "1.0.0",
  "description": "Dai Huu Develop Seafood Manager",
  "main": "daihuudsf_server.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "daihuudsf_server.js"
  },
  "keywords": [
    "mysql",
    "restful"
  ],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.18.2",
    "express": "^4.16.2",
    "formidable": "^1.1.1",
    "socket.io": "*",
    "socketio-file-upload": "^0.4.4",
    "mysql": "^2.15.0"
  }
}

package.json như trên có chỉ định start script. Gỏ lệnh npm start sẽ tương đương với node daihuudsf_server.js

Install PM2

Of course that you want your application daemonized (in background) and of course that you want your application to start when the system is restarting. PM2 will provide all of this.

Stop your Node.js application (ctrl + C) and proceed to installation.

We will use npm to install PM2 globally -g.

sudo npm install -g pm2

Start the application with PM2

To start app.js with PM2 run

pm2 start app.js

and you should see

[PM2] Starting /home/pi/app.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ app      │ 0  │ N/A     │ fork │ 738 │ online │ 0       │ 0s     │ 0%  │ 21.8 MB   │ pi   │ disabled │
└──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘

Now app.js is daemonized running. You can test it as we did before with:

curl localhost:3000

Bonus: if the app crashes, PM2 will restart it.

PM2 startup

The pm2 startup command will generate a script that will lunch PM2 on boot together with the applications that you configure to start.

pm2 startup systemd

will generate

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

Copy the generated command and run it.

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

This created a system unit that will start PM2 on boot. When the system will boot PM2 will resurrect from a dump file that is not created yet. To create it run

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.

That’s it! Your application is currently running and in case of a restart, it will start when the system boots.

PM2 daemon

You will be able to check anytime the status of your application with pm2 listpm2 status or pm2 show.

$ pm2 list
┌──────────┬────┬─────────┬──────┬─────┬────────┬─────────┬────────┬──────┬───────────┬──────┬──────────┐
│ App name │ id │ version │ mode │ pid │ status │ restart │ uptime │ cpu  │ mem       │ user │ watching │
├──────────┼────┼─────────┼──────┼─────┼────────┼─────────┼────────┼──────┼───────────┼──────┼──────────┤
│ app      │ 0  │ N/A     │ fork │ 451 │ online │ 0       │ 96m    │ 0.2% │ 31.8 MB   │ pi   │ disabled │
└──────────┴────┴─────────┴──────┴─────┴────────┴─────────┴────────┴──────┴───────────┴──────┴──────────┘
$ pm2 show app
┌───────────────────┬──────────────────────────────────┐
│ status            │ online                           │
│ name              │ app                              │
│ version           │ N/A                              │
│ restarts          │ 0                                │
│ uptime            │ 97m                              │
│ script path       │ /home/pi/app.js                  │
│ script args       │ N/A                              │
│ error log path    │ /home/pi/.pm2/logs/app-error.log │
│ out log path      │ /home/pi/.pm2/logs/app-out.log   │
│ pid path          │ /home/pi/.pm2/pids/app-0.pid     │
│ interpreter       │ node                             │
│ interpreter args  │ N/A                              │
│ script id         │ 0                                │
│ exec cwd          │ /home/pi                         │
│ exec mode         │ fork_mode                        │
│ node.js version   │ 11.10.0                          │
│ node env          │ N/A                              │
│ watch & reload    │ ✘                                │
│ unstable restarts │ 0                                │
│ created at        │ 2019-02-17T14:14:35.027Z         │
└───────────────────┴──────────────────────────────────┘

There is a lot of greatness within PM2 that you can use, read more about logs and processes below. Running PM2 & Node.js in Production Environments Nick Parsons

Make use of a Reverse Proxy

As I mentioned before, none of the ports on your devices are publicly open yet, so you cannot access your Raspberry Pi from the outer world. There are a ton of reason why you should or shouldn’t use a reverse proxy for your Node.js application. Because of scalability and security reasons (and also is really simple to setup and manage), I will use Nginx as a Reverse Proxy Server for this application.

0. Don’t use a Reverse Proxy 🙁

If you plan to use a Reverse Proxy don’t follow this step otherwise you will mess up the ports (like having 80 and 3000 opened at the same time).

An uncomplicated way to go without a Reverse Proxy is to use ufw to allow some of the ports to allow incoming traffic. But note that this might be a big security flaw.

Install it by running

sudo apt-get install ufw

A quick sudo ufw status verbose will show us that ufw is currently inactive. Before you enable it, you should allow all the SSH traffic to your device, so the connection is not disturbed.

$ sudo ufw allow ssh
Rules updated
Rules updated (v6)

Now you can enable it.

sudo ufw enable

Another quick sudo ufw status verbose will show that all incoming SSH traffic is allowed. All the outgoing traffic is allowed, so don’t worry about it. Now just go on and allow connections on 3000, the port of your application.

sudo ufw allow 3000

Now you can access from the outside of the world! You can type your device’s address followed by the port in your browser.

Outer world

1. Install NGINX

I used Nginx as a Reverse Proxy Server to redirect all the traffic to/from port 80 to my application, on port 3000. Install Nginx running

sudo apt update
sudo apt install nginx

After the installation, Nginx will be running right away. The default port opened is 80 and you can test it by browsing to your Raspberry’s address.

Welcome to Nginx, dev.to

2. Configure the Reverse Proxy Server

There is a lot to say about Reverse Proxies, but we will stick to basics now.

You will edit the default configuration (that serves the HTML page that you saw in your browser) to make the proper redirects.

sudo vim /etc/nginx/sites-available/default

If you are not familiar to Nginx, /etc/nginx/sites-available/default is a long, confusing file. I will get rid of all the comments so you can see it better.

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
            # First attempt to serve request as file, then
            # as directory, then fall back to displaying a 404.
            try_files $uri $uri/ =404;
            # proxy_pass http://localhost:8080;
            # proxy_http_version 1.1;
            # proxy_set_header Upgrade $http_upgrade;
            # proxy_set_header Connection 'upgrade';
            # proxy_set_header Host $host;
            # proxy_cache_bypass $http_upgrade;
        }
}

You will need the basic configuration, therefore leave it be. You will make changes to location / { block.

Uncomment the commented section inside that block, change the port to 3000, get rid of the first lines and that exact configuration is a Reverse Proxy (or just copy the following code).

server {
        listen 80 default_server;
        listen [::]:80 default_server;

        root /var/www/html;

        index index.html index.htm index.nginx-debian.html;

        server_name _;

        location / {
            proxy_pass http://localhost:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
}

Check for syntax errors in Nginx with

sudo nginx -t

and finally restart the Nginx server.

sudo systemctl restart nginx

Test it out by browsing to your Raspberry’s address.

Finally the needed outer world

Done! All the requests to your Raspberry’s address will be redirected to your Node.js application.

Note that this is a basic configuration of Nginx, you can discover more about other features here. Understanding nginx (proxying, reverse proxying, load balancing) Osita Chibuike

Finale

Now you are done! So you got a Node.js application running (daemonized) on a headless Raspberry Pi that deals with requests through an Nginx Reverse Proxy Server.

Hopefully, this was a comprehensive enough guide, but I am open to discussions and questions below. Let us know what you’ve experienced or what other alternatives you found on the way.

Leave a Reply

Your email address will not be published. Required fields are marked *