Chuyển đến nội dung chính

Quản lí ứng dụng Node.js trong Production với Systemd Service và Journalctl

Hướng dẫn triển khai ứng dụng Node.js, Go hoặc Python dưới dạng Systemd Service trên Linux: Tự động khởi động lại khi crash, quản lý biến môi trường, giới hạn bộ nhớ RAM và theo dõi log thời gian thực với Journalctl.

Quản lý ứng dụng với Systemd Service

Tại sao nên dùng Systemd thay vì PM2 hoặc Nohup?

Khi chạy ứng dụng backend (Node.js, Express, NestJS, Go, Python FastAPI...) trên máy chủ Linux, bạn cần đảm bảo ứng dụng luôn chạy ngầm, tự khởi động lại khi gặp lỗi crash và tự động bật lên mỗi khi máy chủ VPS khởi động lại.

Nhiều lập trình viên mới thường sử dụng lệnh nohup node app.js & hoặc cài đặt công cụ quản lý PM2. Tuy nhiên, trong các môi trường doanh nghiệp lớn, Systemd (hệ thống khởi tạo và quản lí dịch vụ mặc định của Linux) mới là giải pháp tối ưu nhất:

  • Không cần cài thêm thư viện phụ thuộc: Systemd được tích hợp sẵn ở mức nhân hệ điều hành Linux (PID 1).
  • Quản lý tài nguyên mạnh mẽ: Tích hợp cgroups cho phép giới hạn trực tiếp CPU, RAM và số lượng tiến trình con (threads).
  • Quản lý log tập trung: Tích hợp trực tiếp với journald và tự động quay vòng file log (Log Rotation) chống tràn ổ đĩa.
  • Độ tin cậy tuyệt đối: Không bao giờ bị crash như các process manager tầng người dùng.

Trong bài viết này, chúng ta sẽ từng bước đóng gói một ứng dụng Node.js thành một dịch vụ Systemd Unit Service chuẩn Production.


1. Chuẩn bị thư mục ứng dụng và non-root user

Không bao giờ chạy ứng dụng web trực tiếp dưới quyền root. Chúng ta sẽ tạo một tài khoản dịch vụ hệ thống riêng (Service Account):

bash
# Tạo user hệ thống không có quyền đăng nhập shell trực tiếp (ví dụ: nodeapp)
sudo useradd -r -s /bin/false -d /var/www/my-app nodeapp

# Tạo thư mục chứa mã nguồn ứng dụng
sudo mkdir -p /var/www/my-app

Giả sử file khởi động chính của ứng dụng nằm tại /var/www/my-app/dist/server.js hoặc index.js.

Phân quyền sở hữu thư mục cho user nodeapp:

bash
sudo chown -R nodeapp:nodeapp /var/www/my-app

2. Quản lý Biến môi trường (.env) an toàn

Tạo file chứa các biến môi trường cấu hình tại /var/www/my-app/.env.production:

bash
sudo nano /var/www/my-app/.env.production

Nội dung:

ini
NODE_ENV=production
PORT=3000
DATABASE_URL=postgres://pgadmin:[email protected]:5432/my_db
REDIS_URL=redis://127.0.0.1:6379
JWT_SECRET=super_secret_jwt_key_here

Phân quyền bảo mật nghiêm ngặt (chỉ cho phép user nodeapp được đọc file này):

bash
sudo chmod 600 /var/www/my-app/.env.production
sudo chown nodeapp:nodeapp /var/www/my-app/.env.production

3. Tạo file Systemd Service Unit (my-app.service)

Tạo file định nghĩa dịch vụ tại /etc/systemd/system/my-app.service:

bash
sudo nano /etc/systemd/system/my-app.service

Dán cấu hình chuẩn Production hoàn chỉnh dưới đây:

ini
[Unit]
Description=My Production Node.js Web API Service
After=network.target postgresql.service redis.service
Wants=network-online.target

[Service]
Type=simple
User=nodeapp
Group=nodeapp
WorkingDirectory=/var/www/my-app

# Đọc các biến môi trường từ file bảo mật
EnvironmentFile=/var/www/my-app/.env.production

# Lệnh thực thi ứng dụng (sử dụng đường dẫn tuyệt đối của node)
ExecStart=/usr/bin/node /var/www/my-app/dist/server.js

# Tự động khởi động lại khi ứng dụng bị crash
Restart=always
RestartSec=5s

# Giới hạn khởi động lại (tránh vòng lặp restart liên tục khi code có lỗi cú pháp)
StartLimitIntervalSec=60s
StartLimitBurst=5

# Giới hạn tài nguyên phần cứng (Memory Limit)
MemoryHigh=800M
MemoryMax=1024M
TasksMax=1000

# Tối ưu giới hạn file mở (File Descriptors) cho Web Server chịu tải cao
LimitNOFILE=65535

# Tăng cường bảo mật Sandbox
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target

Giải thích các tham số quan trọng:

  • After=network.target postgresql.service: Đảm bảo dịch vụ mạng và cơ sở dữ liệu đã sẵn sàng trước khi ứng dụng khởi chạy.
  • Restart=always & RestartSec=5s: Nếu ứng dụng bị Unhandled Exception dẫn đến crash, Systemd sẽ tự động khởi động lại sau 5 giây.
  • MemoryMax=1024M: Giới hạn tối đa 1GB RAM. Nếu ứng dụng vượt quá mức này, Systemd sẽ tự động kill và restart lại dịch vụ để bảo vệ máy chủ.
  • ProtectSystem=full: Ngăn ứng dụng ghi đè lên các thư mục hệ điều hành quan trọng như /usr, /boot, /etc.

4. Kích hoạt và Vận hành Dịch vụ

Mỗi khi tạo mới hoặc chỉnh sửa file .service, bạn cần yêu cầu Systemd nạp lại cấu hình:

bash
sudo systemctl daemon-reload

Kích hoạt dịch vụ tự động khởi chạy cùng máy chủ:

bash
sudo systemctl enable my-app

Bắt đầu khởi chạy dịch vụ:

bash
sudo systemctl start my-app

Kiểm tra trạng thái hoạt động:

bash
sudo systemctl status my-app --no-pager

Nếu màn hình hiển thị màu xanh lá cây Active: active (running) thì dịch vụ của bạn đã vận hành hoàn hảo!


5. Theo dõi và Giám sát Log với journalctl

Toàn bộ log console.log()console.error() của ứng dụng Node.js sẽ được chuyển tiếp trực tiếp vào hệ thống quản lý log journald.

Dưới đây là các lệnh theo dõi log thông dụng:

bash
# Xem log thời gian thực (giống tail -f)
sudo journalctl -u my-app -f

# Xem 100 dòng log gần nhất
sudo journalctl -u my-app -n 100 --no-pager

# Xem log ghi nhận trong ngày hôm nay
sudo journalctl -u my-app --since today

# Chỉ xem các log có mức độ cảnh báo hoặc lỗi (Warnings/Errors)
sudo journalctl -u my-app -p err..emerg

6. Quy trình triển khai Code mới (Zero-Downtime Deployment)

Khi bạn đẩy code mới lên máy chủ, quy trình triển khai diễn ra cực kỳ đơn giản và nhanh gọn:

bash
# 1. Chuyển vào thư mục mã nguồn
cd /var/www/my-app

# 2. Kéo code mới và build
git pull origin main
npm ci --production
npm run build

# 3. Phân lại quyền cho user dịch vụ
sudo chown -R nodeapp:nodeapp /var/www/my-app

# 4. Khởi động lại dịch vụ mượt mà
sudo systemctl restart my-app

Bảng tra cứu lệnh Systemd thiết yếu

LệnhÝ nghĩa
sudo systemctl start <service>Khởi động dịch vụ
sudo systemctl stop <service>Dừng dịch vụ
sudo systemctl restart <service>Khởi động lại dịch vụ
sudo systemctl reload <service>Nạp lại cấu hình mà không ngắt kết nối
sudo systemctl enable <service>Cho phép tự chạy khi bật máy
sudo systemctl disable <service>Tắt tính năng tự chạy
sudo systemctl is-active <service>Kiểm tra nhanh trạng thái (running/inactive)

Lời kết

Sử dụng Systemd Service là giải pháp bản địa (native), nhẹ nhất, nhanh nhất và chuẩn mực nhất để đưa bất kỳ ứng dụng backend nào lên môi trường sản xuất Linux.

💬

Thảo luận & Bình luận

Đăng nhập bằng tài khoản GitHub để đặt câu hỏi hoặc đóng góp ý kiến cho bài viết.