Tài liệuỨng dụng Node.js

Ứng dụng Node.js

Deploy Next.js, Nuxt, NestJS, Express và các server Node.js khác với đúng phiên bản Node, PORT, file lưu cố định, chế độ cluster, rollback và log.

ZoPanel chạy server Node.js như một dịch vụ systemd của tài khoản hosting, phía sau nginx; nginx lo tên miền, SSL và giới hạn request. Dùng trang này khi dự án có package.json và chạy một tiến trình server. Với bản build front-end chỉ sinh ra file tĩnh (Vite, Create React App, Angular, Next.js xuất tĩnh), xem Website tĩnh. Quy trình deploy chung cho mọi ngôn ngữ được mô tả ở Git deploy.

Điều kiện cần

  • Máy chủ đã cài ít nhất một phiên bản Node.js (trình cài đặt mặc định cài Node.js 22).
  • Một website loại Git deploy, hoặc bất kỳ website nào có tab Deploy (ví dụ Node / Proxy).
  • Gói hosting của tài khoản phải có Git deploy & ứng dụng. Nếu không, panel báo "this feature is not included in your hosting package".

Cài các phiên bản Node.js (quản trị viên)

  1. Mở Runtime trong menu quản trị.
  2. Ở mục Runtime khác, tìm thẻ Node.js.
  3. Bấm Node 24, Node 22, Node 20 hoặc Node 18. Có thể cài song song nhiều phiên bản.

ZoPanel tải bản phát hành mới nhất của phiên bản chính đó từ nodejs.org, kiểm tra checksum SHA-256, cài vào /opt/zopanel/runtimes/node/<major> và cài kèm pnpm, yarn. Có thể gỡ các phiên bản đã cài ngay trên thẻ này.

Lưu ý: Node.js 18 và 20 đã hết vòng đời hỗ trợ theo lịch phát hành Node.js. Dự án mới nên dùng 22 hoặc 24.

Ứng dụng dùng phiên bản nào

Nguồn (lấy cái tìm thấy đầu tiên) Ví dụ Kết quả
.nvmrc 22 hoặc v22.11.0 bản chính 22
.node-version 24.1.0 bản chính 24
engines.node trong package.json ">=20" bản chính 20 (con số đầu tiên)
không có các file trên bản mới nhất đã cài

Nếu phiên bản chính được yêu cầu chưa cài, hệ thống dùng bản mới nhất đã cài. Bạn cũng có thể tự chọn: tắt Tự nhận diện trong thẻ Build & chạy rồi chọn ở Phiên bản (Bản mới nhất đã cài = bản mới nhất).

Mẹo: engines.node: ">=18" sẽ chọn Node.js 18 nếu máy chủ có cài. Hãy ghi đúng bản chính bạn muốn vào .nvmrc.

Nhận diện

Mỗi lần deploy, trừ khi Tự nhận diện đang tắt, ZoPanel đọc package.json và điền cấu hình build. Dự án có composer.json được xem là PHP, trừ khi nó dùng một framework server Node. Tương tự, ứng dụng web Python (có manage.py, hoặc có django, flask, fastapi, uvicorn hay gunicorn trong các file thư viện Python) được xem là Python khi package.json không có script start lẫn framework server Node; xem Ứng dụng Python.

Trình quản lý package: pnpm-lock.yaml (hoặc "packageManager": "pnpm@…") → pnpm install --frozen-lockfile; yarn.lock (hoặc yarn@…) → yarn install --frozen-lockfile; package-lock.json hoặc npm-shrinkwrap.json → npm ci; còn lại là npm install. Dự án có lockfile của bun được cài bằng npm install. Lệnh build là <pm> run build khi có script build.

Thư viện trong package.json Nhận diện là Lệnh chạy đề xuất
next Next.js script start, nếu không có thì npx next start
nuxt Nuxt node .output/server/index.mjs
@remix-run/serve, @react-router/serve, @remix-run/node Remix / React Router script start, nếu không có thì npx remix-serve build/index.js
@sveltejs/kit kèm adapter-node SvelteKit node build
astro kèm @astrojs/node Astro node ./dist/server/entry.mjs
@nestjs/core NestJS npm run start:prod nếu có script đó, nếu không thì node dist/main
express, fastify, koa, hono hoặc các thư viện khác Express / Fastify / Koa / Hono / Node.js script start, nếu không có thì node <main>, node server.js, node index.js hoặc node app.js

Next.js với output: 'export', Astro không có @astrojs/node, SvelteKit dùng adapter-static và dự án Vite không có script start được deploy dưới dạng website tĩnh. Nếu có Procfile với dòng web:, dòng đó luôn được dùng làm lệnh chạy.

Bấm Phân tích repository trong tab Deploy để xem kết quả trước khi deploy, rồi bấm Dùng cấu hình này và tuỳ chỉnh để sửa. Các ghi chú như "Could not find a start script; set the start command manually" hiển thị bên dưới cấu hình.

Deploy ứng dụng

  1. Vào Website → Thêm website, chọn Git deploy, nhập Địa chỉ repository, Nhánh và, với monorepo, Thư mục gốc, rồi bấm Tạo website.
  2. Theo dõi lần deploy đầu tiên trong log tác vụ. ZoPanel clone mã nguồn, chạy lệnh cài đặt và build, khởi động ứng dụng và chuyển lưu lượng sang khi ứng dụng đạt health check.
  3. Muốn đổi lệnh, mở tab Deploy, tắt Tự nhận diện trong Build & chạy, sửa các ô rồi bấm Lưu & deploy.

Để deploy không qua Git, chọn File đã tải lên (Quản lý file) ở Nguồn, tải dự án lên domains/<tên-miền>/source rồi bấm Deploy.

PORT và HOST

Ứng dụng phải lắng nghe tại 127.0.0.1, trên cổng nằm trong biến môi trường PORT. ZoPanel đặt sẵn PORT (mỗi slot blue/green một cổng khác nhau) và HOST=127.0.0.1; bạn không ghi đè được hai biến này.

// Express
const port = process.env.PORT || 3000;
app.listen(port, "127.0.0.1");
// NestJS: main.ts
await app.listen(process.env.PORT ?? 3000, "127.0.0.1");

next start, server build của Nuxt, adapter-node của SvelteKit và @astrojs/node của Astro tự đọc PORT. Đừng bao giờ ghi cứng số cổng.

Biến môi trường

Thêm biến trong thẻ Biến môi trường, hoặc bấm Dán .env để dán nhiều biến một lúc. Sau đó bấm Lưu & deploy lại.

  • Tối đa 200 biến. Tên chỉ gồm chữ, số và _, không bắt đầu bằng số; giá trị là một dòng, tối đa 8.192 ký tự.
  • Biến dùng được trong lệnh cài đặt, lệnh build và khi chạy. Thành viên chỉ có quyền xem thấy tên biến, không thấy giá trị.
  • NODE_ENV=production chỉ được đặt khi ứng dụng chạy. Lúc build biến này không được đặt, nên npm ci vẫn cài devDependencies (TypeScript, Vite…). Quan trọng: nếu bạn tự thêm NODE_ENV=production, biến đó áp dụng cả khi build và npm sẽ bỏ qua devDependencies, thường làm build lỗi.
  • Khi build, CI=true được đặt sẵn.

Đường dẫn lưu trữ cố định

Mỗi lần deploy build vào một thư mục mới trong domains/<tên-miền>/releases/, nên file ứng dụng ghi vào đó sẽ mất ở bản release sau. Liệt kê thư mục hoặc file cần giữ trong Đường dẫn lưu trữ cố định, cách nhau bằng dấu phẩy, ví dụ uploads, .env.

  • Chúng được lưu trong domains/<tên-miền>/shared/ và được liên kết vào mọi bản release. Ở lần deploy đầu, nội dung có sẵn trong repository tại đường dẫn đó được sao chép sang.
  • Tên bắt đầu bằng .env được xem là file, còn lại là thư mục.
  • Quan trọng: khi .env là đường dẫn lưu trữ cố định và website có biến môi trường, ZoPanel ghi lại shared/.env từ các biến đó ở mỗi lần deploy. Hãy giữ cấu hình ở một nơi duy nhất.

Chế độ cluster (dùng mọi nhân CPU)

Một tiến trình Node.js chỉ dùng một nhân CPU. Thẻ Dùng mọi nhân CPU (chỉ với ứng dụng server Node.js) chạy một worker cho mỗi CPU gói hosting cho phép, tối đa 16, không cần sửa code: ZoPanel nạp trước một helper nhỏ dùng module cluster của Node, các worker dùng chung cổng.

  1. Đảm bảo ứng dụng không giữ dữ liệu trong RAM: session, cache, bộ đếm rate limit và phòng websocket phải nằm ở Redis hoặc database.
  2. Bật Chạy một tiến trình trên mỗi nhân CPU (deploy lại để áp dụng). Đổi công tắc này sẽ khởi động một lần deploy.

Worker bị lỗi được khởi động lại sau một giây; nếu lỗi nhanh liên tiếp quá 20 lần, ứng dụng dừng và log ghi [zopanel] workers keep crashing, stopping. Muốn dùng ít worker hơn, đặt biến ZP_CLUSTER_WORKERS trong biến môi trường.

Deploy không gián đoạn và rollback

Mỗi ứng dụng server có hai slot. Bản release mới khởi động ở slot đang rảnh, trên cổng riêng, và phải trả lời Đường dẫn health check (mặc định /) với mã HTTP dưới 500 trong vòng 90 giây. Chỉ khi đó nginx mới chuyển sang bản mới; tiến trình cũ được dừng sau vài giây để các request đang xử lý kịp hoàn tất. Bản release build lỗi, thoát hoặc không đạt health check sẽ bị bỏ, bản đang chạy vẫn tiếp tục phục vụ.

Thẻ Các bản release giữ 5 bản build gần nhất. Rollback khởi động bản được chọn ở slot rảnh với cấu hình hiện tại và chuyển sang sau khi đạt health check, không gián đoạn. Rollback không build lại.

Lưu ý: trong lúc chuyển, hai bản chạy song song vài giây nên RAM sử dụng cũng tăng gấp đôi trong khoảnh khắc đó.

Nhật ký

  • Log ứng dụng trong tab Deploy hiển thị 400 dòng stdout và stderr mới nhất của cả hai slot. Bật Trực tiếp để theo dõi liên tục.
  • Log build của từng lần deploy nằm ở Tác vụ, hoặc bấm Xem log trong Lịch sử deploy.
  • Tab Nhật ký của website hiển thị access log và error log của nginx.

Giới hạn RAM và CPU

Ứng dụng chạy trong nhóm tài nguyên của tài khoản hosting, nên giới hạn RAM, CPU và số tiến trình của gói áp dụng chung cho mọi website của tài khoản. Thẻ trạng thái hiển thị RAM hiện tại của ứng dụng. Nếu tài khoản hết bộ nhớ, kernel dừng tiến trình và systemd khởi động lại sau một giây.

Để giới hạn heap của V8 thấp hơn RAM của gói, thêm biến môi trường:

NODE_OPTIONS=--max-old-space-size=384

WebSocket

nginx chuyển tiếp header Upgrade và Connection, nên WebSocket và Server-Sent Events hoạt động mà không cần cấu hình thêm. Proxy buffering đã tắt và kết nối không có dữ liệu trong 300 giây sẽ bị đóng, nên hãy gửi ping/heartbeat thường xuyên hơn mức đó. Khi bật chế độ cluster, mỗi worker giữ kết nối riêng, nên hãy dùng adapter dùng chung (ví dụ Redis adapter của Socket.IO) và transport WebSocket.

Xử lý sự cố

Thông báo hoặc hiện tượng Nguyên nhân và cách xử lý
the app did not respond on port … within 90s (it must listen on $PORT) Ứng dụng lắng nghe cổng cố định hoặc bị lỗi trước khi lắng nghe. Hãy đọc process.env.PORT. 25 dòng log cuối được in trong log tác vụ.
the app exited during startup Mở Log ứng dụng: thường do thiếu biến môi trường, chưa build (không thấy .next) hoặc một module không nạp được.
Node.js is not installed — install it under Runtimes Máy chủ chưa có Node.js. Quản trị viên cài ở Runtime.
install failed: … / build failed: … Lệnh bị lỗi; log tác vụ có đầu ra chi tiết. Kiểm tra lockfile có khớp package.json không (npm ci từ chối khi không khớp).
a start command is required for server apps Điền Lệnh chạy, hoặc đổi Loại thành Website tĩnh nếu là bản build front-end.
start command must be a single line (chain commands with &&) Lệnh chỉ được một dòng, tối đa 2.000 ký tự.
port … is already in use by another process (uid …); try again in a few seconds Tiến trình cũ vẫn đang dừng. Deploy lại sau vài giây.
a deployment of this app is already running Chờ lần deploy hiện tại xong.
Lỗi 502 hoặc trang "đang bận" sau khi deploy Tiến trình dừng sau đó (ví dụ hết RAM). Xem Log ứng dụng và RAM của tài khoản ở Tài nguyên.
Build bị dừng hoặc rất chậm Build dùng chung CPU và RAM của gói. Tăng RAM của gói, hoặc giảm RAM cho build bằng NODE_OPTIONS.

Xem thêm


← Git deploy Ứng dụng Python →