Rocky Linux 9生产环境:Node.js应用部署与优化指南
介绍
Node.js是一个用于构建服务器端和网络应用程序的开源JavaScript运行环境。该平台可在Linux、macOS、FreeBSD和Windows上运行。尽管您可以在命令行上运行Node.js应用程序,但本教程将专注于将它们作为服务运行。这意味着它们将在重启或失败时自动重新启动,并且在生产环境中安全可靠。
在本教程中,您将在Rocky Linux 9服务器上设置一个可投入生产的Node.js环境。该服务器将运行由PM2管理的Node.js应用程序,并通过Nginx反向代理为用户提供安全访问应用程序的方式。Nginx服务器将使用由Let’s Encrypt提供的免费证书提供HTTPS服务。
先决条件
在进行本指南之前,假设您具备以下条件:
- 已完成Rocky Linux 9服务器设置,如Rocky Linux 9初始服务器设置指南所述。您应该拥有一个具有sudo权限的非root用户和一个活动的防火墙。
- 一个指向您服务器公共IP的域名。本教程将全程使用
example.com
作为示例域名。 - 已安装Nginx,如如何在Rocky Linux 9上安装Nginx所述。
- Nginx已配置SSL,并使用Let’s Encrypt证书。您可以参考如何在Rocky Linux 9上使用Let’s Encrypt保护Nginx来完成此过程。
- 您的服务器上已安装Node.js。请参考如何在Rocky Linux 9上安装Node.js。
当您完成所有先决条件后,您将在https://example.com/
上拥有一个为您的域名提供默认占位页面的服务器。
第一步 — 创建一个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
将以下代码插入文件中:
// hello.js
const http = require('http');
const hostname = '127.0.0.1';
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}/`);
});
这是文章《如何在Rocky Linux 9上为生产环境设置Node.js应用程序》的第2部分(共4部分)。
内容片段:
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应用程序监听指定的地址(本地主机)和端口(3000),并以200 HTTP
成功代码返回“Hello World!”。由于我们在本地主机上监听,远程客户端无法连接到我们的应用程序。
要测试您的应用程序,请输入:
- node hello.js
您将会收到以下的输出结果。
Server running at http://localhost:3000/
注意:以这种方式运行Node.js应用程序将阻塞其他命令,直到通过按下CTRL+C
来终止应用程序。为了测试应用程序,请在您的服务器上打开另一个终端会话,并通过curl
连接到本地主机。
- curl http://localhost:3000
如果您得到以下输出,则表示应用程序正常工作并正在正确的地址和端口上进行监听:
Hello World!
如果您没有得到预期的输出,请确保您的Node.js应用程序正在运行并配置为在正确的地址和端口上侦听。
确认应用程序正常运行后,请按下CTRL+C
键关闭应用程序(如果您还没有关闭的话)。
第二步 – 安装PM2
安装和配置PM2
这是文章《如何在Rocky Linux 9上为生产环境设置Node.js应用程序》的第3部分(共4部分)。
接下来,让我们安装PM2,这是一个用于Node.js应用程序的进程管理器。PM2可以将应用程序守护化,使其作为后台服务持续运行。
使用npm在你的服务器上安装最新版本的PM2。
- sudo npm install pm2@latest -g
-g
选项告诉npm在全局安装该模块,使其在整个系统范围内可用。
让我们首先使用 pm2 start
命令在后台运行你的应用程序 hello.js
。
- pm2 start hello.js
这也会将您的应用程序添加到PM2的进程列表中,每次启动应用程序时会输出该列表。
... [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
... [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
... [ '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
行。
这是文章《如何在Rocky Linux 9上为生产环境设置Node.js应用程序》的第4部分(共4部分)。
[Unit]
Description=PM2 进程管理器
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 Essentials: Working with Services, Units, and the Journal》。
除了我们已经涵盖的内容之外,PM2 还提供了许多子命令,可以让您管理或查询有关您的应用程序的信息。
使用该命令停止一个应用程序(请指定 PM2 应用的名称或 ID)。
pm2 stop app_name_or_id
重启一个应用程序:
pm2 restart app_name_or_id
列出当前由 PM2 管理的应用程序。
pm2 list
使用应用名称获取有关特定应用程序的信息。
pm2 info app_name
可以使用 monit
子命令调出 PM2 进程监视器。这将显示应用程序的状态、CPU 和内存使用情况。
pm2 monit
请注意,运行 pm2
不带任何参数也会显示帮助页面及示例用法。
既然您的 Node.js 应用程序正在运行并由 PM2 管理,那么让我们设置反向代理。
第三步 – 将 Nginx 设置为反向代理服务器
您的应用正在本地运行和监听,但是您需要设置一种方式让用户访问它。我们将设置 Nginx 作为反向代理服务器来实现这个目的。
在先决教程中,您需要在 /etc/nginx/conf.d/your_domain.conf
文件中设置您的 Nginx 配置。打开这个文件进行编辑。
sudo nano /etc/nginx/conf.d/your_domain.conf
在服务器块内部,您应该有一个现有的 location /
块。将该块的内容替换为以下配置。如果您的应用程序设置为侦听不同的端口,请将突出显示的部分更新为正确的端口号。
您的域名配置文件位于 /etc/nginx/conf.d/your_domain.conf
。
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
上可用,通过 Web 浏览器访问 https://your_domain/
会将请求发送到位于本地主机监听端口 3000 的 hello.js
。
您可以在同一个服务器块中添加额外的 location
块,以便让其他应用程序在同一服务器上获得访问权限。例如,如果您还在 3001 端口上运行另一个 Node.js 应用程序,您可以添加这个 location
块来通过 https://您的域名/app2
访问它。
/etc/nginx/conf.d/your_domain.conf
— 可选项
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;
}
...
}
完成添加应用程序的 location
模块后,请保存文件并退出编辑器。
请确保您在编辑时没有引入任何语法错误。
sudo nginx -t
重启 Nginx:
sudo systemctl restart nginx
假设您的 Node.js 应用程序正在运行,且应用程序和 Nginx 的配置正确,您现在应该能够通过 Nginx 反向代理访问您的应用程序。尝试通过访问服务器的 URL(公共 IP 地址或域名)来验证。
结论
恭喜!您现在已经在一个 Rocky Linux 9 服务器上使用 Nginx 反向代理运行您的 Node.js 应用程序。这个反向代理设置足够灵活,可以让您的用户访问您想分享的其他应用程序或静态网络内容。
接下来,您可能想了解如何使用 Docker 构建 Node.js 应用程序。