# Ứng dụng Node.js và Python

> Chạy ứng dụng Node.js, Python, Go và các ngôn ngữ khác sau nginx với cổng tự cấp, lệnh chạy, phát hành blue/green không gián đoạn, Node.js đa nhân và log trực tiếp.

Source: https://zopanel.net/vi/docs/apps-node-python  
Updated: 2026-10-07

Ứng dụng server (Node.js, Python, Go, Ruby, Java, .NET) chạy như một dịch vụ của tài khoản hosting, phía sau nginx; nginx lo tên miền, SSL và file tĩnh. ZoPanel build và khởi động ứng dụng qua tab **Deploy** của website, giữ ứng dụng luôn chạy và tự khởi động lại khi tiến trình bị dừng bất thường.

## Cài runtime

Quản trị viên cài runtime ngôn ngữ ở mục **Runtime**:

| Runtime | Phiên bản | Dùng cho |
| --- | --- | --- |
| Node.js | 24, 22, 20, 18 (cài song song được) | Next.js, Nuxt, NestJS, Express và build front-end. Đã kèm pnpm và yarn. |
| Python | Python 3 của hệ thống, dùng môi trường ảo | Django, Flask, FastAPI |
| Go | Bản mới nhất | Dịch vụ viết bằng Go |
| Composer | Bản mới nhất | Laravel và Symfony |
| Ruby, Java, .NET | Gói hệ thống (.NET 8.0) | Rails/Rack, Spring Boot, ASP.NET Core |

Nếu dự án yêu cầu một phiên bản Node.js chính chưa được cài (trong `.nvmrc`, `.node-version` hoặc `engines.node`), hệ thống dùng phiên bản mới nhất đã cài.

## Tạo website

Có hai cách:

- **Git deploy** (khuyên dùng): ở **Website → Thêm website**, chọn **Git deploy** và nhập repository. Xem [Git deploy](/vi/docs/git-deploy).
- **Node / Proxy**: chọn **Node / Proxy** để tạo website chuyển mọi request tới cổng của ứng dụng, sau đó cấu hình ứng dụng ở tab **Deploy** với nguồn **File đã tải lên (Quản lý file)**: tải dự án lên `domains/<tên-miền>/source` bằng Quản lý file hoặc SFTP rồi bấm **Deploy**.

## Cổng

Ứ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 biến này:

- Mỗi website có một cổng gốc riêng, hiển thị là **Cổng nội bộ** trong tab **Deploy** (`127.0.0.1:<cổng>`).
- Để phát hành blue/green, slot thứ hai dùng cổng gốc cộng 10000. Đừng ghi cứng số cổng: luôn đọc biến `PORT`.
- Với tài khoản khách hàng, cổng proxy của website do ZoPanel cố định, không trỏ được sang dịch vụ nội bộ khác. Chỉ quản trị viên mới đặt được **Cổng ứng dụng** khác trong tab **PHP & cấu hình**.

Ví dụ:

```js
// Node.js (Express)
app.listen(process.env.PORT, "127.0.0.1");
```

```python
# Python: gắn server vào $PORT, ví dụ trong lệnh chạy
# .venv/bin/gunicorn myproject.wsgi:application --bind 127.0.0.1:$PORT
```

## Lệnh chạy

ZoPanel đề xuất lệnh chạy dựa trên dự án. Bạn sửa được ở **Build & chạy → Lệnh chạy** (một dòng; nối các bước bằng `&&`).

| Framework | Lệnh chạy đề xuất |
| --- | --- |
| Next.js | `npm run start` (hoặc `npx next start`) |
| Nuxt | `node .output/server/index.mjs` |
| NestJS | `npm run start:prod` hoặc `node dist/main` |
| Express, Fastify, Koa, Hono | `npm run start`, hoặc `node <main>` / `server.js` / `index.js` / `app.js` |
| Django | `.venv/bin/gunicorn <project>.wsgi:application --bind 127.0.0.1:$PORT` |
| FastAPI | `.venv/bin/uvicorn main:app --host 127.0.0.1 --port $PORT` |
| Flask | `.venv/bin/gunicorn app:app --bind 127.0.0.1:$PORT` |
| Go | `./bin/<tên module>` (build bằng `go build -o bin/…`) |
| Dự án có Procfile | dòng `web:` |

Với Python, lệnh cài đặt tạo môi trường ảo trong `.venv` và cài theo `requirements.txt`, `pyproject.toml` hoặc `Pipfile`; gunicorn hoặc uvicorn được thêm nếu thiếu. Với Django, hãy thêm tên miền vào `ALLOWED_HOSTS` (hoặc đọc từ biến môi trường).

Đặt secret và cấu hình trong **Biến môi trường**. Biến dùng được khi build và khi chạy; thành viên có quyền chỉ xem không thấy giá trị của biến.

## Phát hành không gián đoạn (blue/green)

Mỗi ứng dụng server có hai slot. Một bản phát hành mới:

1. được build trong thư mục release riêng;
2. khởi động ở slot đang rảnh, trên cổng của slot đó;
3. phải trả lời ở **Đường dẫn health check** (mặc định `/`) với mã dưới 500 trong vòng 90 giây;
4. chỉ khi đó mới nhận lưu lượng: nginx reload nhẹ nhàng sang slot mới và slot cũ được dừng.

Nếu bản mới build lỗi, thoát khi khởi động hoặc không bao giờ đạt health check, bản đang chạy không bị ảnh hưởng. **Rollback** trong thẻ **Các bản release** (giữ 5 bản build gần nhất) dùng đúng cơ chế này.

Vì hai bản có thể chạy song song trong chốc lát, hãy lưu dữ liệu cần giữ qua các lần phát hành trong database, Redis hoặc **Đường dẫn lưu trữ cố định** (ví dụ `uploads`, `.env`), không lưu trong thư mục release.

## Dùng mọi nhân CPU (Node.js)

Node.js chỉ chạy trên một nhân. Với ứng dụng server Node.js, thẻ **Dùng mọi nhân CPU** chạy một tiến trình trên mỗi nhân CPU của gói mà không cần sửa code, xử lý được gấp nhiều lần. Chỉ bật **Chạy một tiến trình trên mỗi nhân CPU (deploy lại để áp dụng)** khi ứng dụng không giữ dữ liệu trong RAM: session, cache và websocket nên lưu ở Redis hoặc database.

## Khởi động, dừng và khởi động lại

Thẻ trạng thái trong tab **Deploy** hiển thị trạng thái, framework, runtime và cổng nội bộ của ứng dụng, cùng các nút **Deploy ngay**, **Khởi động lại**, dừng và bật ứng dụng. Dịch vụ tự khởi động lại khi tiến trình thoát.

Tài nguyên ứng dụng dùng được tính vào gói hosting: RAM, CPU và số tiến trình của mọi website và ứng dụng hiển thị ở mục **Tài nguyên**.

## Nhật ký

- **Log ứng dụng** trong tab **Deploy** hiển thị 400 dòng mới nhất ứng dụng ghi ra (stdout và stderr, 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 trong **Tác vụ**.
- Tab **Nhật ký** hiển thị access log và error log của nginx. Lỗi 502 ở đây thường do ứng dụng không lắng nghe trên `$PORT`; **Chạy chẩn đoán** sẽ phát hiện và gợi ý cách sửa.

## Xử lý sự cố

| Hiện tượng | Cần kiểm tra |
| --- | --- |
| "The app did not respond on port … within 90s" | Ứng dụng phải lắng nghe tại `127.0.0.1:$PORT`, không dùng cổng cố định. |
| "The app exited during startup" | Xem **Log ứng dụng**: thường do thiếu biến môi trường hoặc thư viện. |
| "Node.js is not installed — install it under Runtimes" | Nhờ quản trị viên cài một phiên bản Node.js. |
| Health check trả về 404 hoặc chuyển hướng | Mọi mã dưới 500 đều đạt. Mã 5xx nghĩa là ứng dụng đang lỗi; hãy đặt **Đường dẫn health check** là một route trả lời nhanh. |
