如何在Debian10上为生产设置Node.js应用程序
介绍
Node.js 是用于构建服务器端和网络应用程序的开源 JavaScript 运行时环境。 该平台在 Linux、macOS、FreeBSD 和 Windows 上运行。 尽管您可以在命令行上运行 Node.js 应用程序,但本教程将重点关注将它们作为服务运行。 这意味着应用程序将在重新启动或失败时重新启动,并且可以在生产环境中安全使用。
在本教程中,您将在单个 Debian 10 服务器上设置生产就绪的 Node.js 环境。 该服务器将运行由 PM2 管理的 Node.js 应用程序,并通过 Nginx 反向代理为用户提供对应用程序的安全访问。 Nginx 服务器将提供 HTTPS,使用 Let's Encrypt 提供的免费证书。
先决条件
本指南假定您具备以下条件:
- Debian 10 服务器设置,如 Debian 10 的 初始服务器设置指南中所述。 您应该有一个具有
sudo
权限的非 root 用户和一个活动的防火墙。 - 域名指向您服务器的公共 IP 。
- 已安装 Nginx,如 How To Install Nginx on Debian 10 中所述。
- Nginx 使用 Let's Encrypt 证书配置了 SSL。 如何在 Debian 10 上使用 Let's Encrypt 保护 Nginx 将引导您完成整个过程。
完成先决条件后,您将拥有一台服务器,该服务器在 https://your_domain/
处为您的域的默认占位符页面提供服务。
第 1 步 — 安装 Node.js
让我们首先使用 NodeSource 包档案安装最新的 LTS 版本的 Node.js。
要安装 NodeSource PPA 并访问其内容,您首先需要更新包索引并安装 curl
:
sudo apt update sudo apt install curl
确保您位于主目录中,然后使用 curl
检索 Node.js 10.x 档案的安装脚本:
cd ~ curl -sL https://deb.nodesource.com/setup_10.x -o nodesource_setup.sh
您可以使用 nano
或您的 首选文本编辑器 检查此脚本的内容:
nano nodesource_setup.sh
检查完脚本后,在 sudo
下运行它:
sudo bash nodesource_setup.sh
PPA 将添加到您的配置中,并且您的本地包缓存将自动更新。 从 Nodesource 运行安装脚本后,您可以安装 Node.js 包:
sudo apt install nodejs
要在这些初始步骤之后检查您安装了哪个版本的 Node.js,请键入:
nodejs -v
Outputv10.16.0
注意: 从 NodeSource PPA 安装时,Node.js 可执行文件称为 nodejs
,而不是 node
。
nodejs
包包含 nodejs
二进制文件以及 npm,一个 Node 模块的包管理器,因此您不需要单独安装 npm
.
npm
使用主目录中的配置文件来跟踪更新。 它将在您第一次运行 npm
时创建。 执行此命令以验证 npm
是否已安装并创建配置文件:
npm -v
Output6.9.0
为了使某些 npm
包能够工作(例如,那些需要从源代码编译代码的包),您需要安装 build-essential
包:
sudo apt install build-essential
您现在拥有使用需要从源代码编译代码的 npm
包的必要工具。
安装 Node.js 运行时后,我们可以继续编写 Node.js 应用程序。
第 2 步 — 创建 Node.js 应用程序
让我们编写一个 Hello World 应用程序,它向任何 HTTP 请求返回“Hello World”。 此示例应用程序将帮助您设置 Node.js。 您可以将其替换为您自己的应用程序 — 只需确保修改您的应用程序以侦听适当的 IP 地址和端口即可。
首先,让我们创建一个名为 hello.js
的示例应用程序:
cd ~ nano hello.js
在文件中插入以下代码:
~/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}/`); });
保存文件并退出编辑器。
此 Node.js 应用程序侦听指定地址 (localhost
) 和端口 (3000
),并返回“Hello World!” 带有 200
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
来终止应用程序(如果你还没有)。
第 3 步 — 安装 PM2
接下来让我们安装 PM2,一个 Node.js 应用程序的进程管理器。 PM2 使守护应用程序成为可能,以便它们作为服务在后台运行。
使用 npm
在您的服务器上安装最新版本的 PM2:
sudo npm install pm2 -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. ┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐ │ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │ ├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤ │ hello │ 0 │ fork │ 1338 │ online │ 0 │ 0s │ 0% │ 23.0 MB │ sammy │ disabled │ └──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘ Use `pm2 show <id|name>` to get more details about an app
如您所见,PM2 会根据不带 .js
扩展名的文件名自动分配 App name
以及 PM2 id
。 PM2 还维护其他信息,例如进程的PID
、当前状态和内存使用情况。
如果应用程序崩溃或被杀死,在 PM2 下运行的应用程序将自动重新启动,但我们可以使用 startup
子命令采取额外的步骤让应用程序在系统启动时启动。 此子命令生成并配置启动脚本以在服务器启动时启动 PM2 及其托管进程。 键入以下内容:
sudo pm2 startup
您将看到如下输出,描述 PM2 生成的服务配置:
Output[PM2] Init System found: systemd Platform systemd Template [Unit] Description=PM2 process manager Documentation=https://pm2.keymetrics.io/ After=network.target [Service] Type=forking User=root LimitNOFILE=infinity LimitNPROC=infinity LimitCORE=infinity Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin Environment=PM2_HOME=/root/.pm2 PIDFile=/root/.pm2/pm2.pid Restart=on-failure ExecStart=/usr/lib/node_modules/pm2/bin/pm2 resurrect ExecReload=/usr/lib/node_modules/pm2/bin/pm2 reload all ExecStop=/usr/lib/node_modules/pm2/bin/pm2 kill [Install] WantedBy=multi-user.target Target path /etc/systemd/system/pm2-root.service Command list [ 'systemctl enable pm2-root' ] [PM2] Writing init configuration in /etc/systemd/system/pm2-root.service [PM2] Making script booting at startup... [PM2] [-] Executing: systemctl enable pm2-root... Created symlink /etc/systemd/system/multi-user.target.wants/pm2-root.service → /etc/systemd/system/pm2-root.service. [PM2] [v] Command successfully executed. +---------------------------------------+ [PM2] Freeze a process list on reboot via: $ pm2 save [PM2] Remove init script via: $ pm2 unstartup systemd
您现在已经创建了一个 systemd unit,它在启动时运行 pm2
。 这个 pm2
实例依次运行 hello.js
。
使用 systemctl
启动服务:
sudo systemctl start pm2-root.service
检查 systemd 单元的状态:
systemctl status pm2-root.service
您应该看到如下输出:
Output● pm2-root.service - PM2 process manager Loaded: loaded (/etc/systemd/system/pm2-root.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2019-07-12 16:09:54 UTC; 4s ago
有关 systemd 的详细概述,请参阅 Systemd Essentials: Working with Services, Units, and the Journal 。
除了我们已经介绍的那些之外,PM2 还提供了许多子命令,允许您管理或查找有关您的应用程序的信息。
使用此命令停止应用程序(指定 PM2 App name
或 id
):
pm2 stop app_name_or_id
重新启动应用程序:
pm2 restart app_name_or_id
列出当前由 PM2 管理的应用程序:
pm2 list
使用 App name
获取有关特定应用程序的信息:
pm2 info app_name
PM2 过程监视器可以使用 monit
子命令启动。 这将显示应用程序状态、CPU 和内存使用情况:
pm2 monit
请注意,不带任何参数运行 pm2
也会显示一个带有示例用法的帮助页面。
现在您的 Node.js 应用程序正在由 PM2 运行和管理,让我们设置反向代理。
第 4 步 — 将 Nginx 设置为反向代理服务器
您的应用程序正在 localhost
上运行和侦听,但您需要为用户设置访问它的方式。 为此,我们将 Nginx Web 服务器设置为反向代理。
在先决条件教程中,您在 /etc/nginx/sites-available/your_domain
文件中设置了 Nginx 配置。 打开此文件进行编辑:
sudo nano /etc/nginx/sites-available/your_domain
在 server
块中,您应该有一个现有的 location /
块。 将该块的内容替换为以下配置。 如果您的应用程序设置为侦听不同的端口,请将突出显示的部分更新为正确的端口号:
/etc/nginx/sites-available/your_domain
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/
会将请求发送到 hello.js
,监听端口 3000
在 [ X157X]。
您可以将额外的 location
块添加到同一服务器块,以提供对同一服务器上其他应用程序的访问。 例如,如果您还在端口 3001
上运行另一个 Node.js 应用程序,则可以添加此位置块以允许通过 https://your_domain/app2
访问它:
/etc/nginx/sites-available/your_domain — 可选
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 反向代理访问您的应用程序。 通过在浏览器中访问您的域来尝试一下:https://your_domain
。
结论
恭喜! 现在,您的 Node.js 应用程序在 Debian 10 服务器上的 Nginx 反向代理后面运行。 这种反向代理设置足够灵活,可以让您的用户访问您想要共享的其他应用程序或静态 Web 内容。