介紹
Node.js 是一個用於構建伺服器端和網絡應用程序的開源JavaScript運行時環境。該平台可在Linux、macOS、FreeBSD和Windows上運行。儘管您可以在命令行上運行Node.js應用程序,但本教程將重點介紹如何將它們作為服務運行。這意味著它們將在重新啟動或失敗時重新啟動,並且可以安全地在生產環境中使用。
在本教程中,您將在一個單獨的Rocky Linux 9服務器上設置一個適用於生產的Node.js環境。該服務器將運行一個由PM2管理的Node.js應用程序,並通過Nginx反向代理為用戶提供安全訪問該應用程序。Nginx服務器將使用由Let’s Encrypt提供的免費證書提供HTTPS。
先決條件
本指南假設您具有以下條件:
- A Rocky Linux 9 server setup, as described in the initial server setup guide for Rocky Linux 9. You should have a non-root user with sudo privileges and an active firewall.
- A domain name pointed at your server’s public IP. This tutorial will use the domain name example.com throughout.
- Nginx已安裝,如在Rocky Linux 9上安裝Nginx的方法所述。
- Nginx 使用 Let’s Encrypt 憑證進行 SSL 配置。如何在 Rocky Linux 9 上使用 Let’s Encrypt 保護 Nginx將引導您完成該過程。
- 在您的伺服器上安裝了 Node.js。如何在 Rocky Linux 9 上安裝 Node.js
完成先決條件後,您將在https://example.com/
上為您的域名提供默認佔位頁面。
步驟 1 — 創建 Node.js 應用程式
讓我們編寫一個Hello World應用程式,以對任何 HTTP 請求返回“Hello World”。此示例應用程式將幫助您啟動並運行 Node.js。您可以將其替換為您自己的應用程式 —— 只需確保您修改應用程式以聆聽適當的 IP 地址和端口。
Rocky Linux 9 預設的文本編輯器是vi
。vi
是一個非常強大的文本編輯器,但對於缺乏經驗的用戶來說可能有些難以理解。您可能希望安裝一個更加用戶友好的編輯器,如nano
,以便於編輯 Rocky Linux 9 伺服器上的配置文件:
- sudo dnf install nano
現在,使用 nano
或您喜歡的文字編輯器,創建一個名為 hello.js
的示例應用程序:
- nano hello.js
將以下代碼插入文件中:
const http = require('http');
const hostname = 'localhost';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
保存文件並退出編輯器。如果使用 nano
,按 Ctrl+X
,然後在提示時按 Y
,然後按 Enter。
此 Node.js 應用程序在指定的地址(localhost
)和端口(3000
)上聽取,並返回帶有 200
的“Hello World!” HTTP 成功碼。由於我們正在聽取 localhost
,遠程客戶端將無法連接到我們的應用程序。
要測試應用程序,輸入:
- node hello.js
您將收到以下輸出:
OutputServer running at http://localhost:3000/
注意:以這種方式運行 Node.js 應用程序將阻止其他命令,直到通過按 CTRL+C
來終止應用程序。
要測試應用程序,在您的服務器上打開另一個終端會話,並使用 curl
連接到 localhost
:
- curl http://localhost:3000
如果您獲得以下輸出,則應用程序正常運行並在正確的地址和端口上聽取:
OutputHello World!
如果未獲得預期的輸出,請確保您的 Node.js 應用程序正在運行並配置為聽取正確的地址和端口。
確保它正常運行後,通過按 CTRL+C
來終止應用程序(如果尚未終止)。
步驟 2 — 安裝 PM2
接下來讓我們安裝 PM2,這是一個用於 Node.js 應用程式的進程管理器。PM2 可以將應用程式守護起來,讓它們作為服務在背景運行。
使用 npm
在您的伺服器上安裝最新版本的 PM2:
- sudo npm install pm2@latest -g
使用 -g
選項告訴 npm
將模組安裝 全域性地,這樣它就可以在整個系統中使用。
讓我們首先使用 pm2 start
命令在背景運行您的應用程式 hello.js
:
- pm2 start hello.js
這也將您的應用程式添加到 PM2 的進程列表中,每次啟動應用程式時都會輸出:
Output...
[PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /home/sammy/hello.js in fork_mode (1 instance)
[PM2] Done.
┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
│ id │ name │ mode │ ↺ │ status │ cpu │ memory │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0 │ hello │ fork │ 0 │ online │ 0% │ 25.2mb │
└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘
如上所示,PM2 自動分配一個 應用程式名稱
(根據文件名,不含 .js
擴展名)和一個 PM2 id
。PM2 還維護其他信息,例如進程的 PID
、當前狀態和內存使用情況。
在 PM2 下運行的應用程式如果崩潰或被終止,將會自動重新啟動,但我們可以採取額外的步驟,使用 startup
子命令讓應用程式在系統啟動時啟動。此子命令會生成並配置一個啟動腳本以在伺服器啟動時啟動 PM2 及其管理的進程:
- pm2 startup systemd
Output…
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
複製並運行提供的命令(這是為了避免以 sudo
運行 Node.js 工具時出現權限問題):
- sudo env PATH=$PATH:/usr/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
Output…
[ 'systemctl enable pm2-sammy' ]
[PM2] Writing init configuration in /etc/systemd/system/pm2-sammy.service
[PM2] Making script booting at startup...
[PM2] [-] Executing: systemctl enable pm2-sammy...
Created symlink /etc/systemd/system/multi-user.target.wants/pm2-sammy.service → /etc/systemd/system/pm2-sammy.service.
[PM2] [v] Command successfully executed.
+---------------------------------------+
[PM2] Freeze a process list on reboot via:
$ pm2 save
[PM2] Remove init script via:
$ pm2 unstartup systemd
現在,您需要對剛剛生成的系統服務進行編輯,以使其與Rocky Linux的SELinux安全系統兼容。 使用nano
或您喜歡的文本編輯器,打開/etc/systemd/system/pm2-sammy.service
:
- sudo nano /etc/systemd/system/pm2-sammy.service
在配置文件的[Service]
塊中,將PIDFile
設置的內容替換為下面突出顯示的/run/pm2.pid
,並添加其他突出顯示的Environment
行:
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target
[Service]
Type=forking
User=sammy
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/home/sammy/.local/bin:/home/sammy/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/usr/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/sammy/.pm2
PIDFile=/run/pm2.pid
Restart=on-failure
Environment=PM2_PID_FILE_PATH=/run/pm2.pid
ExecStart=/usr/local/lib/node_modules/pm2/bin/pm2 resurrect
ExecReload=/usr/local/lib/node_modules/pm2/bin/pm2 reload all
ExecStop=/usr/local/lib/node_modules/pm2/bin/pm2 kill
[Install]
保存並關閉文件。您現在已經創建了一個在啟動時為您的用戶運行pm2
的systemd 單元。 這個pm2
實例又運行hello.js
。
使用systemctl
啟動服務:
- sudo systemctl start pm2-sammy
檢查systemd單元的狀態:
- systemctl status pm2-sammy
有關systemd的詳細概述,請參閱Systemd基本知識:使用服務、單元和日誌。
除了我們已經介紹的內容外,PM2還提供了許多子命令,允許您管理或查找有關應用程序的信息。
使用此命令停止應用程序(指定PM2的應用程序名稱
或id
):
- pm2 stop app_name_or_id
重新啟動應用程序:
- pm2 restart app_name_or_id
列出PM2當前管理的應用程序:
- pm2 list
使用其應用程序名稱
獲取有關特定應用程序的信息:
- pm2 info app_name
PM2 進程監控器可以使用 monit
子命令拉起。這會顯示應用程序狀態、CPU 和內存使用情況:
- pm2 monit
請注意,運行 pm2
而不帶任何參數也會顯示帶有示例用法的幫助頁面。
現在,您的 Node.js 應用程序正在運行並由 PM2 管理,讓我們設置反向代理。
第三步 — 設置 Nginx 為反向代理服務器
您的應用程序正在運行並監聽在 localhost
上,但您需要設置一種方式讓用戶訪問它。我們將設置 Nginx Web 服務器作為反向代理來達到此目的。
在先決教程中,您在 /etc/nginx/conf.d/your_domain.conf
文件中設置了 Nginx 配置。打開此文件進行編輯:
- sudo nano /etc/nginx/conf.d/your_domain.conf
在 server
塊內,您應該有一個現有的 location /
塊。將該塊的內容替換為以下配置。如果您的應用程序設置為監聽不同的端口,請將突出顯示部分更新為正確的端口號:
server {
...
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
...
}
這樣配置伺服器以回應位於其根目錄的請求。假設我們的伺服器位於 your_domain
,透過網頁瀏覽器訪問 https://your_domain/
將發送請求至在 localhost
上監聽端口 3000
的 hello.js
。
您可以在同一伺服器區塊中添加額外的 location
區塊,以提供對同一伺服器上其他應用程序的訪問。例如,如果您還在端口 3001
上運行另一個 Node.js 應用程序,您可以添加此位置區塊以允許通過 https://your_domain/app2
訪問它:
server {
...
location /app2 {
proxy_pass http://localhost:3001;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
...
}
在為應用程序添加位置區塊後,請保存文件並退出您的編輯器。
確保您未引入任何語法錯誤,請輸入:
- sudo nginx -t
重新啟動 Nginx:
- sudo systemctl restart nginx
假設您的 Node.js 應用程序正在運行,且應用程序和 Nginx 配置正確,您現在應該能夠通過 Nginx 反向代理訪問您的應用程序。嘗試通過訪問伺服器的 URL(公共 IP 地址或域名)來測試。
結論
恭喜!您現在已經將您的 Node.js 應用程序運行在 Rocky Linux 9 伺服器的 Nginx 反向代理後。此反向代理設置足夠靈活,可以讓您的用戶訪問其他應用程序或您想共享的靜態網頁內容。
接下來,您可能想了解如何使用Docker建立一個Node.js應用程式。How to build a Node.js application with Docker。