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

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

Đây là phần 2 của bài viết về cách deploy ứng dụng NodeJs lên VPS.

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:

bash
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:

bash
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:

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

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

bash
sudo ufw status

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

bash
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:

bash
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:

bash
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:

bash
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

bash
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:

bash
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:

bash
nvm list-remote
bash
...
        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:

bash
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:

bash
nvm list
bash
> 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:

bash
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:

bash
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:

bash
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

bash
cd /home

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

bash
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:

bash
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:

bash
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:

bash
node index.js

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

bash
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:

bash
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:

bash
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.

bash
                        -------------

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


                          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:

bash
pm2 startup systemd

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

bash
[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:

bash
pm2 save

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

bash
systemctl start pm2-root

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

bash
systemctl status pm2-root

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

bash
● 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:

bash
pm2 stop

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

bash
pm2 restart app_name_or_id

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

bash
pm2 list

Xem thông tin ứng dụng:

bash
pm2 info app_name

Hết phần 2

Bài viết liên quan