Hướng dẫn deploy Node.js app lên VPS Linux Ubuntu

 


Lời mở đầu

Với sự phát triển của ngành phần mềm hiện nay, việc chạy ứng dụng Node.js trên máy chủ ảo Ubuntu là một lựa chọn tối ưu cho các nhà phát triển. Nhờ vào tính ổn định và hiệu quả của hệ thống Ubuntu, ứng dụng của bạn sẽ luôn hoạt động mượt mà và sẵn sàng phục vụ người dùng. Vì thế trong bài viết này chúng ta sẽ tìm hiểu cách deploy Node.js app lên VPS Linux Ubuntu

Tại sao deploy Node.js app trên VPS Linux Ubuntu?

Trước tiên chúng ta hãy nói về ưu điểm của VPS:

  • Tính linh hoạt: Dễ dàng cấu hình và điều chỉnh theo nhu cầu của ứng dụng.
  • Khả năng tùy chỉnh cao: Cung cấp quyền kiểm soát chi tiết đối với môi trường triển khai.
  • Khả năng mở rộng: Có thể nâng cấp tài nguyên khi nhu cầu sử dụng tăng cao.

Và lợi ích của việc sử dụng Linux Ubuntu đó là hệ thống ổn định đảm bảo hoạt động trơn tru, bảo mật cao giảm thiểu nguy cơ bị tấn công và xâm nhập và cộng đồng hỗ trợ lớn cung cấp nhiều tài nguyên hướng dẫn.

Mục tiêu bài viết

Bài viết này sẽ hướng dẫn các bạn từng bước triển khai ứng dụng Node.js lên VPS chạy hệ điều hành Linux Ubuntu. Các bạn sẽ học cách cài đặt môi trường Node.js, cấu hình máy chủ VPS, và triển khai ứng dụng của mình sao cho hoạt động một cách hiệu quả và bảo mật.

Chuẩn bị trước khi deploy Node.js app

Để bắt đầu vào deploy Node.js app lên VPS Linux Ubuntu thì các bạn cần chuẩn bị những thứ dưới đây:

  • VPS chạy hệ điều hành Linux Ubuntu: Khuyến khích cài đặt Ubuntu bản từ 18.04 trở lên. Nếu chưa có VPS các bạn có thể đăng ký tại inet.vn và nhập mã LAHOTECHCP để được giảm giá khi đăng ký.
  • Tên miền (domain): Tên miền đã trỏ đến IP của VPS. Nếu bạn nào chưa có tên miền có thể đăng ký tại inet.vn.
  • Ứng dụng Node.js: Đã được upload lên các dịch vụ lưu trữ mã nguồn như Github.
  • Công cụ SSH: Dùng để kết nối với VPS từ xa. Ở đây mình sử dụng MobaXterm.

Sau khi chuẩn bị xong những thứ trên chúng ta bắt đầu thôi.

Cài đặt Nginx cho VPS Ubuntu

Cài đặt Nginx

Vì Nginx có sẵn trong gói cài đặt của Ubuntu nên chúng ta có thể dễ dàng cài đặt bằng cách sử dụng apt. Trước tiên để đảm bảo các bản cập nhật và gói phần mềm mới nhất chúng ta cần cập nhật cơ sở dữ liệu của các gói phần mềm bằng cách chạy lệnh dưới đây:

sudo apt update

Tiếp theo cài đặt nginx, trong lúc cài đặt các bạn cần phải bấm Y (Yes) để xác nhận cho apt cài thêm các gói thư viện cần thiết cho nginx:

sudo apt install nginx

Thiết lập tường lửa (Firewall)

Trước khi chúng ta thiết lập service Nginx, cần phải thiết lập tường lửa để cho phép truy cập vào nó. Nginx nó sẽ tự đăng ký một service với ufw khi cài đặt. Vì thế chúng ta có thể thiết lập tường lửa để cho phép truy cập vào service Nginx dễ dàng hơn.

Liệt kê tất cả các configuration của ứng dụng mà ufw có thể thiết lập:

sudo ufw app list

Nó sẽ in ra tất cả danh sách các profiles của ứng dụng mà chúng ta có thể thiết lập Firewall:

Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH

Trong danh sách trên có 3 profile cho Nginx:

  • Nginx Full: Đây là profile mở cả 2 port 80 và 443 (TLS/SSL encrypted traffic)
  • Nginx HTTP: Profile này chỉ mở cổng 80
  • Nginx HTTPS: Profile này chỉ mở cổng 443

Vì chúng ta chưa cài đặt SSL cho Nginx, nên chúng ta sẽ mở port 80 để thử nghiệm xem service Nginx có hoạt động như mong muốn hay không.

Chúng ta sẽ mở cổng 80 bằng lệnh sau:

sudo ufw allow 'Nginx HTTP'
Rules updated
Rules updated (v6)

Sau đó kiểm tra lại status bằng lệnh:

sudo ufw status

Nếu bạn nào không hiện output như dưới đây thì hãy xuống dưới sang bước kế tiếp. Còn bạn nào có output như dưới đây thì là do chưa enable ufw, các bạn enable bằng lệnh sau:

sudo ufw enable

Nếu nó hỏi Command may disrupt existing ssh connections. Proceed with operation (y|n)? các bạn bấm y để xác nhận nhé.

Bây giờ chúng ta sẽ kiểm tra lại status và kết quả hiện ra như sau:

Status: active

To                         Action      From
--                         ------      ----
Nginx HTTP                 ALLOW       Anywhere
Nginx HTTP (v6)            ALLOW       Anywhere (v6)

Sau khi thiết lập tường lửa bây giờ chúng ta có thể kiểm tra web server đã hoạt động hay chưa

Lưu ý:
Một lưu ý quan trọng là chúng ta cần phải cho ufw allow cả OpenSSH vì lúc chúng ta enable ufw lên thì nó sẽ không tự động add rule OpenSSH vào nên không kết nối tới VPS bằng SSH được. Nếu quên bước này thì trong lần kết nối tiếp theo tới VPS sẽ không được.Chạy lệnh: sudo ufw allow 'OpenSSH' sau đó kiểm tra lại status ufw

Một lưu ý quan trọng là chúng ta cần phải cho ufw allow cả OpenSSH vì lúc chúng ta enable ufw lên thì nó sẽ không tự động add rule OpenSSH vào nên không kết nối tới VPS bằng SSH được. Nếu quên bước này thì trong lần kết nối tiếp theo tới VPS sẽ không được.Chạy lệnh: sudo ufw allow 'OpenSSH' sau đó kiểm tra lại status ufw

Kiểm tra Web Server

Khi quá trình cài đặt xong thì Ubuntu sẽ start Nginx lên và web server đã hoạt động. Kiểm tra systemd xem để chắc chắn rằng service đã và đang hoạt động

systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
     Active: active (running) since Sun 2024-03-03 09:17:37 UTC; 28min ago
       Docs: man:nginx(8)
    Process: 11020 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
    Process: 11021 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
   Main PID: 11127 (nginx)
      Tasks: 3 (limit: 2237)
     Memory: 4.6M
        CPU: 67ms
     CGroup: /system.slice/nginx.service
             ├─11127 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"
             ├─11130 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""
             └─11131 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""

Mar 03 09:17:37 lahocore systemd[1]: Starting A high performance web server and a reverse proxy server...
Mar 03 09:17:37 lahocore systemd[1]: Started A high performance web server and a reverse proxy server.

Output ở trên các bạn sẽ kiểm tra thấy dòng Active: active (running) nghĩa là service Nginx đã hoạt động.

Bây giờ mở trình duyệt lên và truy cập tới địa chỉ IP VPS của các bạn. Nếu các bạn không nhớ thì có thể chạy lên sau:

ip addr show eth0 | grep inet | awk '{ print $2; }' | sed 's/\/.*$//'

Sau khi có được IP của máy chủ VPS thì truy cập trên trình duyệt như sau http://ip_vps_server và kết quả như hình dưới đây

Thiết lập Server Blocks

Ở bước này, chúng ta sẽ config tên miền cho web server. Hãy đảm bảo rằng tên miền của các bạn đã trỏ về IP của VPS.

Trong thư mục /etc/nginx/sites-available/ tạo một fiel mới với tên là tên miền của các bạn. Ví dụ tên miền của mình là example.com thì sẽ tạo file là /etc/nginx/sites-available/example.com. Chúng ta sẽ tạo bằng lệnh sau:

sudo nano /etc/nginx/sites-available/example.com

Chỉnh sửa nội dung như dưới đây:

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

        server_name example.com www.example.com;

        location / {
                try_files $uri $uri/ =404;
        }
}

Bấm Ctrl + X -> Y sau đó bấm Enter để lưu lại file.

Tiếp theo, kích hoạt file này bằng cách liên kết nó tới thư mục sites-enabled của nginx, nơi mà nó sẽ đọc trong khi khởi động:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

Để tránh tình trạng vấn đề bộ nhớ hash bucket có thể phát sinh khi thêm các server names bổ sung, cần config giá trị biến server_names_hash_bucket_size trong file /etc/nginx/nginx.conf. Mở file nginx.conf lên:

sudo nano /etc/nginx/nginx.conf

Tìm đến dòng có server_names_hash_bucket_size sau đó xoá kí tự # để uncomment dòng này:

...
http {
    ...
    server_names_hash_bucket_size 64;
    ...
}
...

Sau đó bấm Ctrl + X -> Y -> Enter để lưu lại file.

Tiếp theo chạy lệnh dưới đây để kiểm tra xem không có cú pháp nào lỗi trong các file cấu hình Nginx:

sudo nginx -t

Nếu như hiện như dưới đây thì không có vấn đề gì

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

Sau đó thì restart lại Nginx

sudo systemctl restart nginx

Cấu hình SSL/TLS cho web server Nginx bằng Let's Encrypt

Cài đặt Certbot

Đầu tiên để sử dụng Let's Encrypt để nhận một chứng chỉ SSL là cài đặt Certbot trên máy chủ của chúng ta.

sudo snap install --classic certbot

Khi cài đặt thành công sẽ in ra phiên bản của Certbot

certbot 2.9.0 from Certbot Project (certbot-eff✓) installed

Sau đó tạo một liên kết tượng trưng (symbolic link) tới tệp thực thi certbot (/snap/bin/certbot) mà chúng ta vừa cài đặt từ thư mục /usr/bin/. Bước này đảm bảo rằng lệnh certbot có thể chạy đúng trên máy chủ của chúng ta. Để làm điều này, chúng ta sẽ chạy lệnh ln sau đây. Lệnh này chứa flag -s để tạo một liên kết tượng trưng (symbolic link) hoặc liên kết mềm, không phải là một liên kết cứng:

sudo ln -s /snap/bin/certbot /usr/bin/certbot

Kiểm tra lại cấu hình Nginx

Chạy lệnh dưới đây. Nếu không có lỗi nào được tìm thấy, nó sẽ xuất ra một thông báo "syntax is ok" "test is successful" xác nhận rằng cấu hình là hợp lệ.

sudo nginx -t

Nếu có lỗi, hãy mở lại tệp khối máy chủ đã cấu hình ở phần server block và kiểm tra xem có bất kỳ lỗi chính tả hoặc ký tự nào bị thiếu không. Khi cú pháp của tệp cấu hình là chính xác, hãy tải lại Nginx để tải cấu hình mới.

sudo systemctl reload nginx

Cho phép kết nối HTTPS thông qua Firewall

Kiểm tra cấu hình hiện tại của ufw:

sudo ufw status

Chúng ta sẽ thấy output như dưới đây, nghĩa là chỉ có lưu lượng HTTP được phép tới web server:

Status: active

To                         Action      From
--                         ------      ----
Nginx HTTP                 ALLOW       Anywhere
OpenSSH                    ALLOW       Anywhere
Nginx HTTP (v6)            ALLOW       Anywhere (v6)
OpenSSH (v6)               ALLOW       Anywhere (v6)

Bây giờ để cho phép lưu lượng HTTPS, chúng ta cần phải cho phép cả profile Nginx Full và xóa quyền cho phép không cần thiết của profile Nginx HTTP. Chúng ta sẽ thực hiện như dưới đây:

sudo ufw allow 'Nginx Full'
sudo ufw delete allow 'Nginx HTTP'

Sau đó kiểm tra lại status của ufw:

sudo ufw status

Chúng ta sẽ có output như dưới đây:

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
Nginx Full                 ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
Nginx Full (v6)            ALLOW       Anywhere (v6)

Cài đặt SSL Certificate

Certbot cung cấp nhiều cách để đạt được chứng chỉ SSL thông qua các plugin. Plugin Nginx sẽ tự động config lại Nginx và tải lại config khi cần thiết. Để sử dụng plugin này, chúng ta có thể chạy lệnh sau:

sudo certbot --nginx -d example.com -d example.com
  • certbot là lệnh để tương tác với Certbot.
  • --nginx chỉ định rằng chúng ta đang sử dụng plugin Nginx để tự động cấu hình lại Nginx.
  • -d example.com được sử dụng để chỉ định tên miền của chúng ta muốn đạt được chứng chỉ SSL cho nó. Có thể thêm nhiều tên miền bằng cách thêm thêm flag -d other_domain

Khi lần đầu tiên chạy Certbot, chúng ta sẽ được yêu cầu nhập địa chỉ email và đồng ý với các điều khoản dịch vụ. Sau khi làm điều này, Certbot sẽ giao tiếp với máy chủ Let’s Encrypt để yêu cầu một chứng chỉ cho tên miền của chúng ta. Nếu thành công, sẽ nhận được output sau đây:

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2024-06-11.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

Deploying certificate
Successfully deployed certificate for example.com to /etc/nginx/sites-enabled/example.com
Congratulations! You have successfully enabled HTTPS on https://example.com
We were unable to subscribe you the EFF mailing list because your e-mail address appears to be invalid. You can try again later by visiting https://act.eff.org.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le

Kiểm tra Certbot tự động làm mới chứng chỉ

Chứng chỉ của Let’s Encrypt chỉ có hiệu lực trong 90 ngày. Điều này nhằm khuyến khích người dùng tự động hóa quá trình làm mới chứng chỉ của họ. Gói certbot mà chúng ta đã cài đặt sẽ xử lý điều này bằng cách thêm một tập lệnh làm mới vào /etc/cron.d. Tập lệnh này sẽ chạy hai lần mỗi ngày và sẽ tự động làm mới bất kỳ chứng chỉ nào gần hết hạn trong vòng 30 ngày.

Để kiểm tra quá trình này, chúng ta có thể thực hiện một thử nghiệm "dry run" với certbot:

sudo certbot renew --dry-run

Lệnh này sẽ mô phỏng quá trình làm mới chứng chỉ mà không thực sự làm mới chúng. Điều này giúp chúng ta đảm bảo rằng quá trình làm mới được cấu hình đúng và sẵn sàng hoạt động khi chứng chỉ của chúng ta cần được làm mới.

Deploy Node.js app lên VPS Linux Ubuntu

Bây giờ chúng ta sẽ bắt đầu vào phần chính của bài viết này đó là deploy ứng dụng Node.js lên VPS Linux Ubuntu. Ở đây mình sẽ deploy một ứng dụng Node.js + Express.js đã có sẵn của mình ở trên Github, Chúng ta sẽ clone repo đó về và deploy.

Cài đặt Node.js bằng Node Version Manager

Các bạn chạy lần lượt các lệnh sau,

Chạy lệnh dưới đây để cài đặt nvm trước

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

Tiếp theo kích hoạt nvm chạy lệnh:

source ~/.bashrc

Bây giờ liệt kê các phiên bản của Node.js có sẵn để cài đặt thông qua nvm:

nvm list-remote
...
        v19.9.0
        v20.0.0
        v20.1.0
        v20.2.0
        v20.3.0
        v20.3.1
        v20.4.0
        v20.5.0
        v20.5.1
        v20.6.0
        v20.6.1
        v20.7.0
        v20.8.0
        v20.8.1
        v20.9.0   (LTS: Iron)
       v20.10.0   (LTS: Iron)
       v20.11.0   (LTS: Iron)
       v20.11.1   (Latest LTS: Iron)
        v21.0.0
        v21.1.0
        v21.2.0
        v21.3.0
        v21.4.0
        v21.5.0
        v21.6.0
        v21.6.1
        v21.6.2
        v21.7.0
        v21.7.1

Chúng ta có thể cài đặt một phiên bản của Node bằng cách nhập bất kỳ phiên bản phát hành nào được liệt kê như ở trên. Ở đây mình sẽ cài phiên bản v20.11.1 (Latest LTS: Iron), chạy lệnh sau:

nvm install v20.11.1

Chúng ta có thể xem các phiên bản Node.js bạn đã cài đặt bằng cách chạy lệnh:

nvm list
->     v20.11.1
default -> v20.11.1
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v20.11.1) (default)
stable -> 20.11 (-> v20.11.1) (default)
lts/* -> lts/iron (-> v20.11.1)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.20.2 (-> N/A)
lts/hydrogen -> v18.19.1 (-> N/A)
lts/iron -> v20.11.1

Các bạn có thể chuyển đổi giữa các phiên bản Node.js bằng lệnh:

nvm use v20.11.1

Thay v20.11.1 bằng phiên bản bạn muốn sử dụng.

Kiểm tra Git

Nếu các bạn clone project từ về bằng git thì chúng ta sẽ kiểm tra trước đã có sẵn git trên con VPS của mình chưa bằng cách chạy lệnh:

git --version

Nếu output ra version của Git thì bây giờ chúng ta sẽ sang bước tiếp theo. Nếu chưa thì các bạn cài Git bằng lệnh sau:

sudo apt install git-all

Clone ứng dụng Node.js

Đầu tiên mình sẽ chuyển tới thư mục home

cd /home

Sau đó sẽ clone project trên Github về:

git clone github_repo_url

Khi lần đầu tiên chạy git clone thì chúng ta sẽ được hỏi username và password (token) account Github. Các bạn hãy nhập user và password (token) account Github của các bạn để tiếp tục.

Sau khi clone project về, chúng ta sẽ di chuyển vào thư mục của project và cài đặt các dependencies:

cd myapp
npm install

Sau đó chúng ta sẽ chạy thử xem project của chúng ta đã run lên được chưa. Đây là nội dung file index.js của mình:

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`App is listening on: http://localhost:${port}`)
})

Chạy lệnh dưới đây để khởi chạy app:

node index.js

Các bạn sẽ thấy output như sau:

App is listening on: http://localhost:3000

Cài đặt PM2

Tiếp theo, chúng ta sẽ cài đặt PM2, một trình quản lý tiến trình cho các ứng dụng Node.js. PM2 cho phép daemonize các ứng dụng để chúng sẽ chạy ở nền như một dịch vụ (service).

Sử dụng npm để cài đặt PM2 mới nhất trên máy chủ VPS của chúng ta:

npm install pm2@latest -g

Đầu tiên, chúng ta sẽ sử dụng lệnh pm2 start để chạy app của chúng ta, index,js ở dưới nền:

pm2 start index.js

Lệnh này sẽ khởi chạy app của chúng ta index.js bằng PM2 và chạy nó ở chế độ nền. Nó cũng thêm ứng dụng của chúng ta vào danh sách tiến trình của PM2, danh sách này sẽ được xuất ra mỗi khi chúng ta khởi động một ứng dụng. Điều này cho phép chúng dễ dàng quản lý các ứng dụng đang chạy bằng PM2.

                        -------------

__/\\\\\\\\\\\\\____/\\\\____________/\\\\____/\\\\\\\\\_____
 _\/\\\/////////\\\_\/\\\\\\________/\\\\\\__/\\\///////\\\___
  _\/\\\_______\/\\\_\/\\\//\\\____/\\\//\\\_\///______\//\\\__
   _\/\\\\\\\\\\\\\/__\/\\\\///\\\/\\\/_\/\\\___________/\\\/___
    _\/\\\/////////____\/\\\__\///\\\/___\/\\\________/\\\//_____
     _\/\\\_____________\/\\\____\///_____\/\\\_____/\\\//________
      _\/\\\_____________\/\\\_____________\/\\\___/\\\/___________
       _\/\\\_____________\/\\\_____________\/\\\__/\\\\\\\\\\\\\\\_
        _\///______________\///______________\///__\///////////////__


                          Runtime Edition

        PM2 is a Production Process Manager for Node.js applications
                     with a built-in Load Balancer.

                Start and Daemonize any application:
                $ pm2 start app.js

                Load Balance 4 instances of api.js:
                $ pm2 start api.js -i 4

                Monitor in production:
                $ pm2 monitor

                Make pm2 auto-boot at server restart:
                $ pm2 startup

                To go further checkout:
                http://pm2.io/


                        -------------

[PM2] Spawning PM2 daemon with pm2_home=/root/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/myapp/index.js in fork_mode (1 instance)
[PM2] Done.
┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id │ name     │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0  │ index    │ default     │ 1.0.0   │ fork    │ 140692   │ 0s     │ 0    │ online    │ 0%       │ 38.1mb   │ root     │ disabled │
└────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

Các ứng dụng đang chạy dưới PM2 sẽ được khởi động lại tự động nếu ứng dụng đó bị crash hoặc killed, nhưng chúng ta có thể thực hiện một bước bổ sung để cho ứng dụng được khởi chạy khi hệ thống khởi động bằng cách sử dụng lệnh con startup. Lệnh con này tạo ra và cấu hình một script khởi chạy để khởi động PM2 và các tiến trình được quản lý của nó khi hệ thống khởi động:

pm2 startup systemd

Chúng ta sẽ được output như dưới đây:

[PM2] Init System found: systemd
Platform systemd
Template
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=forking
User=root
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/root/.nvm/versions/node/v20.11.1/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/root/.pm2
PIDFile=/root/.pm2/pm2.pid
Restart=on-failure

ExecStart=/root/.nvm/versions/node/v20.11.1/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/root/.nvm/versions/node/v20.11.1/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/root/.nvm/versions/node/v20.11.1/lib/node_modules/pm2/bin/pm2 kill

[Install]
WantedBy=multi-user.target

Target path
/etc/systemd/system/pm2-root.service
Command list
[ 'systemctl enable pm2-root' ]
[PM2] Writing init configuration in /etc/systemd/system/pm2-root.service
[PM2] Making script booting at startup...
[PM2] [-] Executing: systemctl enable pm2-root...
Created symlink /etc/systemd/system/multi-user.target.wants/pm2-root.service → /etc/systemd/system/pm2-root.service.
[PM2] [v] Command successfully executed.
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save

[PM2] Remove init script via:
$ pm2 unstartup systemd

Dưới đây là một số điểm chính của script khởi động được tạo:

  • Script khởi động được lưu tại đường dẫn: /etc/systemd/system/pm2-root.service.
  • PM2 sẽ được chạy dưới quyền root.
  • Script được cấu hình để khởi động PM2 bằng phiên bản Node.js được quản lý bởi NVM (/root/.nvm/versions/node/v20.11.1).
  • Khi hệ thống khởi động lại, script này sẽ tự động được kích hoạt để khởi động PM2.
  • pm2 save sẽ lưu trữ thông tin về các quy trình PM2 đang quản lý để có thể khôi phục lại sau khi hệ thống khởi động lại.
  • pm2 unstartup systemd được sử dụng để gỡ bỏ script khởi động của PM2 từ systemd. Khi chúng ta chạy lệnh này, PM2 sẽ gỡ bỏ script khởi động systemd đã được tạo trước đó để PM2 không còn tự động khởi động cùng với hệ thống.

Ở đây chúng ta sẽ chạy lệnh pm2 save để lưu lại file script khởi động này:

pm2 save

Bây giờ chúng ta sẽ start dịch vụ này bằng systemctl:

systemctl start pm2-root

Sau đó kiểm tra lại status:

systemctl status pm2-root

Chúng ta sẽ được output như dưới đây:

● pm2-root.service - PM2 process manager
     Loaded: loaded (/etc/systemd/system/pm2-root.service; enabled; vendor preset: enabled)
     Active: active (running) since Mon 2024-03-18 14:57:01 UTC; 32s ago
       Docs: https://pm2.keymetrics.io/
    Process: 145513 ExecStart=/root/.nvm/versions/node/v20.11.1/lib/node_modules/pm2/bin/pm2 resurrect (code=exited, status=0/SUCCESS)
   Main PID: 140675 (PM2 v5.3.1: God)
      Tasks: 0 (limit: 2237)
     Memory: 4.0K
        CPU: 688ms
     CGroup: /system.slice/pm2-root.service
             ‣ 140675 "PM2 v5.3.1: God Daemon (/root/.pm2)" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" ""

Mar 18 14:57:00 lahocore systemd[1]: Starting PM2 process manager...
Mar 18 14:57:01 lahocore pm2[145513]: [PM2] Resurrecting
Mar 18 14:57:01 lahocore pm2[145513]: [PM2] Restoring processes located in /root/.pm2/dump.pm2
Mar 18 14:57:01 lahocore pm2[145513]: ┌────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
Mar 18 14:57:01 lahocore pm2[145513]: │ id │ name     │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
Mar 18 14:57:01 lahocore pm2[145513]: ├────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
Mar 18 14:57:01 lahocore pm2[145513]: │ 0  │ index    │ default     │ 1.0.0   │ fork    │ 140692   │ 13m    │ 0    │ online    │ 0%       │ 51.7mb   │ root     │ disabled │
Mar 18 14:57:01 lahocore pm2[145513]: └────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
Mar 18 14:57:01 lahocore systemd[1]: Started PM2 process manager.

Dưới đây là các lệnh của PM2 để các bạn có thể quản lý ứng dụng của mình:

Dừng một ứng dụng trong PM2:

pm2 stop 

Khởi động lại một dứng dụng:

pm2 restart app_name_or_id

Xem danh sách ứng dụng đang chạy trong PM2:

pm2 list

Xem thông tin ứng dụng:

pm2 info app_name

Thiết lập Nginx như một Reverse Proxy Server

Điều này sẽ giúp chuyển hướng yêu cầu từ máy khách tới các máy chủ back-end và xử lý yêu cầu này trước khi gửi đến máy chủ back-end.

Trong bước này, chúng ta sẽ cấu hình Nginx như một máy chủ proxy nghịch đảo để chuyển hướng yêu cầu từ người dùng đến ứng dụng của chúng ta đang chạy trên localhost. Chúng ta sẽ mở tệp cấu hình Nginx đã tạo ở các bước trên (với tên miền example.com) để tiếp tục cấu hình. Mở file cấu hình bằng cách chạy lệnh:

sudo nano /etc/nginx/sites-available/example.com

Trong khối server, chúng ta đã có một khối location / hiện có. Thay thế nội dung của khối đó với cấu hình sau:

...
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;
    }
...

Sau đó lưu lại Ctrl + X -> Y -> Enter.

Cấu hình này nghĩa là khi người dùng truy cập vào địa chỉ https://example.com/, Nginx sẽ chuyển hướng yêu cầu đến ứng dụng của chúng ta đang chạy trên localhost với cổng 3000.

Ví dụ, nếu chúng ta có một ứng dụng Node.js đang chạy trên localhost với tệp index.js và nó lắng nghe trên cổng 3000, mọi yêu cầu gửi đến https://example.com/ sẽ được chuyển tiếp tới index.js thông qua Nginx.

Điều này giúp tạo ra một phản ứng tự động từ phía máy chủ khi người dùng truy cập vào trang chủ của tên miền của chúng ta.

Bây giờ hãy kiểm tra lại nginx có bị lỗi gì không:

sudo nginx -t

Nếu mọi thứ OK hết thì sẽ restart lại nginx:

sudo systemctl restart nginx

Nếu ứng dụng Node.js của chúng ta đang chạy và cấu hình của ứng dụng cũng như cấu hình của Nginx đã được thiết lập đúng, bây giờ chúng ta có thể truy cập vào ứng dụng của mình thông qua máy chủ proxy nghịch đảo của Nginx. Truy cập vào tên miền mà chúng ta đã thiết lập và xem kết quả.

Lời kết

Bài viết hơi dài, nhưng mong nó sẽ giúp ích được cho các bạn! Bây giờ các bạn đã có ứng dụng Node.js của mình đang chạy sau một máy chủ proxy nghịch đảo của Nginx trên một máy chủ VPS Linux Ubuntu. Bạn nào có câu hỏi hoặc gặp khó khăn trong quá trình setup thì có thể nhắn trực tiếp lên page FB nhé!

Trong các bài viết sau mình sẽ hướng dẫn các bạn deploy các ứng dụng như Next.js, Nest.js, v.v lên VPS Linux Ubuntu.

Xem thêm: Next.js 14: Cách Sử Dụng Next Auth cơ bản để xác thực

Cảm ơn các bạn đã theo dõi bài viết!

A wibu guy who likes coding and creating blogs, YouTube, etc.