Node.js được biết tới là môi trường JavaScript runtime đa nền tảng mã nguồn mở nổi tiếng trong giới lập trình web. Không phải bởi vì nguồn tài liệu phong phú mà chính là chỉ cần biết JavaScript, thông qua Node.js bạn sẽ có thể “cân” tốt từ front-end đến back-end. Thêm nữa là hệ sinh thái phong phú với kho thư viện npmjs đồ sộ không khác gì kho plugin của WordPress càng khiến cho Node.js trở nên phổ biến. Vẫn câu hỏi cũ: “mấy cái này thì liên quan gì đến Devilbox?!”.
Do Node.js hỗ trợ đa nền tảng nên việc cài đặt nó cực kỳ đơn giản. Tuy nhiên, đây không phải vấn đề mà tôi muốn đề cập. Thứ tôi muốn đề cập trong nội dung này chính là cách vận hành Node.js với Devilbox. Bây giờ, hãy chuẩn bị một chút.
Để bài hướng dẫn được đơn giản. Tôi sẽ sử dụng lại cấu trúc thư mục đã đề xuất trước đó.
├── devilbox
└── projects
└── expressjs
└── public
└── index.js
Tôi sẽ thử nghiệm Node.js trên Devilbox với ExpressJS. Đây là một Node.js framework khá nổi tiếng vì các tay chơi Node.js mới tập tành thì hầu như đều biết tới nó. Như bạn thấy, thư mục dự án tương ứng có tên là expressjs
.
docker compose up -d
./shell.sh
expressjs
mkdir expressjs && cd expressjs
yarn init -y
yarn add express
index.js
với nội dung như sau:const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening on port ${port}`)
})
Khởi chạy dự án:
node index.js
Mở trình duyệt và truy cập vào tên miền của dự án. Đương nhiên là nó sẽ không hoạt động:
Nếu bạn nào đang có suy nghĩ là do phần cấu hình Virtual Hosts chưa chính xác, hãy thử cấu hình lại xem. Đương nhiên là nó cũng sẽ không hoạt động đâu. Thế nên bây giờ chính thức là lúc chúng ta bắt đầu cấu hình Node.js trên Devilbox.
Trước khi tiếp tục, hãy nói một chút về Reverse Proxy. Nói đơn giản thì đây là một loại ứng dụng trung gian làm nhiệm vụ chuyển tiếp yêu cầu.
Trong ví dụ của chúng ta, nó chính là server nhận request đến từ browser sau đó chuyển nó đến ứng dụng Express. Bởi mặc định, web server của chúng ta chỉ phục vụ hai port là 80
cho HTTP
và 443
cho HTTPS
. Nó hoàn toàn không biết gì port 3000
của ứng dụng Node.js. Thế nên có thể nói việc tạo Reverse Proxy này cũng chính là việc cấu hình sao cho Devilbox chuyển tiếp request từ web server đến ứng dụng của chúng ta.
Việc này thực sự rất đơn giản. Nếu bạn đã tham khảo nội dung về cấu hình mỗi dự án sẽ sử dụng một phiên bản PHP thì nội dung này cũng sẽ tương tự như vậy.
.devilbox
. Bên trong thư mục này, tiếp tục tạo tập tin backend.cfg
. Lúc này cấu trúc dự án sẽ là:├── .devilbox
│ └── backend.cfg
├── index.js
├── package.json
└── yarn.lock
backend.cfg
:conf:rproxy:http:php:3000
Tadaaa! Thành công rực rỡ.
backend.cfg
Nếu bạn còn nhớ thì tập tin này từng được tôi đề cập đến trong nội dung về cấu hình mỗi dự án sử dụng một phiên bản PHP. Nó phụ trách việc tự động tạo Reverse Proxy cho Devilbox. Cấu trúc nội dung tập tin lúc đó là:
conf:phpfpm:tcp:php74:9000
Trong đó:
conf
: mẫu quy định của Devilboxphpfpm
: loại web server. Hiện tại Devilbox hỗ trợ hai loại. Một là PHP-FPM hỗ trợ phiên dịch PHP. Hai là Reverse Proxy như ví dụ trên hỗ trợ proxy tới một ứng dụng chỉ định. Cái này phù hợp với các ứng dụng tự tạo web server riêng như Node.js, Python,…tcp
: protocol – giao thức kết nối. Devilbox hiện tại hỗ trợ ba loại giao thức: TCP, HTTP và Websocket.php74
: hostname của dịch vụ. Điều này đã được đề cập đến trước đây. Đương nhiên bạn có thể đổi nó thành IP tương ứng nếu thích.9000
: port của ứng dụng.Giờ tôi tin bạn đã hiểu được nội dung của tập tin backend.cfg
rồi phải không? Lưu ý rằng với mục protocol, nếu là HTTP và Websocket và bạn đã cấu hình HTTPS thì nên chuyển giá trị sang tương ứng là https
và wss
. Ngoài ra, theo thông tin từ tác giả thì Websocket sẽ không hoạt động với Apache 2.2 nên nếu bạn đang sử dụng Apache hãy chuyển sang sử dụng phiên bản 2.4.
Tới thời điểm này ứng dụng của chúng ta vẫn hoạt động tốt. Điều đó không cần phải bàn. Nhưng chỉ cần bạn khởi động lại Devilbox là mọi thứ sẽ tèo ngay.
Đó là do khi khởi động ứng dụng Node.js bằng câu lệnh node index.js
, chúng ta đã giữ cho ứng dụng chạy foreground bằng terminal. Cho nên khi tắt Devilbox, terminal bị ngắt kết nối nên ứng dụng cũng bị “ngỏm” theo. Cách duy nhất là làm sao cho ứng dụng có thể chạy background hay còn gọi là chạy ngầm như một service của Devilbox.
Cách thực hiện khá là đơn giản vì Devilbox đã hỗ trợ sẵn tính năng autostart với tên thư mục cũng là autostart
ngay trong Devilbox luôn. Chỉ cần đặt các tập tin shell script trong thư mục này thì chúng sẽ tự động được thực thi khi khởi động Devilbox.
Để cho khó khăn thêm một chút, tôi sẽ cài đặt thêm nodemon
và cấu hình để mỗi khi khởi động Devilbox thì dự án expressjs
cũng sẽ tự khởi động theo. Đồng thời, Node.js cũng sẽ tự khởi động lại mỗi khi dự án có sự thay đổi nhằm đáp ứng đúng tinh thần của việc cài đặt môi trường phát triển. Các bước sẽ như sau:
autostart
và tạo một tập tin shell script bất kỳ. Ở đây tôi đặt là autostart-expressjs.sh
.├── devilbox
└── autostart
└── autostart-expressjs.sh
expressjs
vào tập tin autostart-expressjs.sh
.su -c "cd /shared/httpd/expressjs; pm2 start index.js --watch" -l devilbox
Phần nội dung trong dấu nháy kép là câu lệnh truy cập vào thư mục dự án theo đường dẫn trong PHP container, sau đó khởi động ứng dụng với pm2 đã định nghĩa trong package.json
. Toàn bộ câu lệnh được bao bọc trong từ khóa su
nhằm đảm bảo nó sẽ được thực hiện bằng user devilbox
– user mặc định bên trong PHP container.
Lưu ý rằng nếu bạn thay đổi nội dung script trong thư mục autostart thì hãy khởi động lại Devilbox để thấy sự thay đổi.
Các shell script được đặt trong thư mục autostart
sẽ luôn được thực thi khi Devilbox khởi động. Nếu bạn muốn script chỉ được thực thi đối với một phiên bản PHP nhất định, hãy đặt script đó vào thư mục cfg/php-startup-[x]
trong thư mục chứa Devilbox. Trong đo [x]
là phiên bản PHP mà bạn muốn. Ngoài ra, Devilbox cũng đã cài đặt sẵn PM2 cũng như kèm theo ví dụ sẵn với PM2 trong thư mục autostart
, bạn có thể tham khảo và sử dụng luôn nếu thích.
Như đã giới thiệu ở các phần trước, Devilbox đã kèm theo sẵn các loại cơ sở dữ liệu phổ biến: MySQL, PostgreSQL và MongoDB. Dưới đây là thông số kết nối mặc định được cấu hình bởi Devilbox.
Devilbox đã tích hợp sẵn công cụ phpMyAdmin trong menu Tools. Bạn có thể sử dụng nó để quản lý và thao tác với MySQL. Còn đây là thông số cấu hình mặc định:
const host = 'mysql'
const port = 3306
const username = 'root'
const password = ''
Tương tự như trên, Devilbox cũng tích hợp sẵn công cụ Adminer trong menu Tools giúp thao tác với PostgreSQL được dễ dàng hơn. Các thông số mặc định của PostgreSQL sẽ là:
const host = 'pgsql'
const port = 5432
const username = 'root'
const password = ''
Mặc định Devilbox không cấu hình username và password cho MongoDB. Do vậy bạn chỉ cần kết nối trực tiếp là có thể thao tác được ngay:
const host = 'mongo'
const port = 27017
Tiếp tục là thông số kết nối Redis:
const host = 'redis'
const port = 6379
Devilbox cũng tích hợp sẵn công cụ phpRedMin trong menu Tools. Nó sẽ có ích cho bạn trong việc quản lý Redis.
Trên đây là các thông số các loại database thường dùng với các ứng dụng Node.js. Và đến đây thì có vẻ như nội dung về Node.js với Devilbox đã kết thúc nhưng không hề!
Các bạn có để ý rằng khi cài đặt reverse proxy xong thì chúng ta đã không còn sử dụng được PHP-FMP nếu trước đó nó là một dự án PHP hay không? Hãy nghĩ xem nếu đây là một dự án Laravel và tôi cần sử dụng Node.js như môi trường phát triển front-end thôi thì làm thế nào? Hãy tiếp tục với nội dung bên dưới.
Như các bạn biết, khi làm việc với một công cụ Front-end, ví dụ như là Vite chẳng hạn, chúng ta sẽ phải vận hành một server Node.js phục vụ cho quá trình compile các JavaScript module. Việc này khi thực hiện trực tiếp trên môi trường gốc thì hết sức đơn giản. Nhưng khi làm việc với Devilbox thì sẽ có phần phức tạp hơn một chút.
Tôi sẽ lấy ví dụ với Laravel cho đơn giản vì đã được hướng dẫn ở đây. Thứ hai nữa là khi làm việc với Laravel, ít nhiều gì bạn cũng sẽ dùng đến Vite để phát triển và đóng gói mã nguồn cho phía Frontend. Nếu cấu hình theo tài liệu của Laravel thì đến bước khởi động Vite, bạn sẽ gặp thông báo lỗi tương tự như thế này:
Thậm chí, nếu đổi giá trị host của hmr
thành domain hiện tại cũng không khả quan:
Đó là vì virtual host
hiện tại không có cấu hình port 5173
. Nhưng nếu cấu hình lại thì dự án Laravel sẽ không hoạt động nữa. Bởi vì như đã đề cập, cùng một lúc chỉ có một reverse proxy hoạt động mà thôi. Để giải quyết vấn đề này, tôi muốn đề xuất một cấu trúc dự án mới:
├── projects
├── laravel -> laravel.dvl.to
└── vitejs -> vitejs.dvl.to
Chúng ta sẽ tạo thêm một thư mục dự án nữa có tên là vitejs
tương ứng với tên miền vitejs.dvl.to
. Tên miền này nhằm mục đích là làm reverse proxy cho Vite khi vận hành development server. Bởi vì Devilbox hiện tại chỉ chấp nhận một virtual host cho một domain mà thôi. Tôi sẽ tạm thời mô hình hóa nó như sau:
graph LR;
devilbox <----> laravel & vite
laravel[laravel.dvl.to] -- port 80 + websocket --> vite[vitejs.dvl.to];
vite -- port 5173 --> devilbox;
Cũng không có gì gọi là phức tạp đúng không? Bây giờ, tôi sẽ vào các bước chi tiết.
vitejs
. Tôi sẽ tạo thư mục .devilbox
và cấu hình Websocket reverse proxy trong backend.cfg
với nội dung như sau:conf:rproxy:ws:php:5173
Lưu ý: Vite sẽ kết nối và bật tính năng hot reload
thông qua Websocket nên giá trị protocol
ở đây sẽ là ws
. Nhân tiện, tôi cũng sẽ trình bày lại một chút về cấu trúc dự án vitejs
lúc này:
├── vitejs
├── .devilbox
| └── backend.cfg
└── public
vite.config.js
và thay đổi một chút ở phần server như sau:export default defineConfig({
//...
server: {
host: '0.0.0.0',
hmr: {
host: 'vitejs.dvl.to',
clientPort: 80,
},
},
})
npm run dev
Giờ hãy tải lại trang chủ dự án xem nào.
Tadaaa! Thành công rực rỡ.
Lưu ý rằng bạn phải sử dụng web server là Nginx khi sử dụng cách cấu hình này.
Như đã biết, Vite mặc định sử dụng port 5173
. Nếu bạn có ý định đổi port, đừng quên cập nhật lại tập tin backend.cfg
. Đặc biệt nếu sử dụng https
, cũng đừng quên đổi ws
thành wss
đồng thời cập nhật lại clientPort
thành 443
.
Như vậy là nội dung về Node.js với Devilbox đã kết thúc. Tôi tin rằng nó thực sự rất đơn giản vì chỉ cần một tập tin backend.cfg
mà thôi.
Nhắc đến tập tin này, bạn có biết rằng ngoài việc cấu hình bằng tập tin backend.cfg
, Devilbox còn cung cấp một cách khác nữa. Thế nhưng cách này sẽ phức tạp hơn vì sẽ phải “đụng” trực tiếp tới web server. Và đó cũng chính là nội dung kế tiếp trong loạt bài hướng dẫn Devilbox. Let’s go!