介绍
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
HTTP成功代码的“Hello World!”由于我们在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
扩展名)和一个PM2id
。 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安全系统兼容。使用/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]
保存并关闭文件。您现在已经创建了一个systemd 单元,该单元在启动时为您的用户运行pm2
。这个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 管理,让我们设置反向代理。
步骤 3 —— 设置 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
,通过Web浏览器访问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地址或域名)进行测试。
结论
恭喜!您现在已经在Rocky Linux 9服务器上将Node.js应用程序运行在Nginx反向代理后。此反向代理设置足够灵活,可以为您的用户提供访问其他应用程序或要共享的静态Web内容。
下一步,您可能想研究一下如何使用Docker构建Node.js应用程序。