如何在 Ubuntu 20.04 上设置用于生产的 Node.js 应用程序

介绍

Node.js是一个开源的JavaScript运行环境,用于构建服务器侧和网络应用程序. 该平台运行在Linux,macOS,FreeBSD和Windows上. 虽然您可以在命令行运行Node.js应用程序,但本教程将专注于将它们作为服务运行。

在本教程中,您将在一个Ubuntu 20.04 服务器上设置一个生产准备的 Node.js 环境,该服务器将运行由 PM2管理的 Node.js 应用程序,并通过 Nginx 反向代理提供用户安全访问该应用程序, Nginx 服务器将使用 Let's Encrypt提供的免费证书提供 HTTPS。

前提条件

本指南假定您有以下内容:

当您完成前提条件后,您将有一个服务器来服务您的域的默认位置主页在https://example.com/`。

步骤 1 – 安装 Node.js

让我们先安装 Node.js 的最新 LTS 版本,使用 NodeSource包存档。

首先,安装 NodeSource PPA 以获取其内容. 确保您在您的主目录中,并使用弯曲从其档案中获取 Node.js 最新 LTS 版本的安装脚本。

1cd ~
2curl -sL https://deb.nodesource.com/setup_14.x -o nodesource_setup.sh

您可以使用nano或您喜爱的文本编辑器检查本脚本的内容:

1nano nodesource_setup.sh

当你完成检查脚本时,在sudo下运行它:

1sudo bash nodesource_setup.sh

PPA 将被添加到您的配置中,您的本地包缓存将自动更新。从 Nodesource 运行安装脚本后,您可以安装 Node.js 包:

1sudo apt install nodejs

要检查在这些初步步骤后安装了哪个版本的 Node.js,请键入:

1node -v
1[secondary_label Output]
2v14.4.0

<$>[注] 注: 在从 NodeSource PPA 安装时,Node.js 可执行程序被称为nodejs,而不是node

nodejs包包含了nodejs二进制以及npm(https://www.npmjs.com/),它是Node模块的包管理器,因此您不需要单独安装npm

npm 使用您的主目录中的配置文件来跟踪更新. 它将创建在您首次运行 npm. 执行此命令以验证 npm 已安装并创建配置文件:

1npm -v
1[secondary_label Output]
26.14.5

为了使某些npm包工作(例如需要编译源代码的包),您需要安装build-essential包:

1sudo apt install build-essential

您现在有必要的工具来处理需要编译源代码的npm包。

有了 Node.js 运行时间安装,让我们继续写一个 Node.js 应用程序。

步骤 2 — 创建 Node.js 应用程序

让我们写一个 Hello World 应用程序,该应用程序会返回任何 HTTP 请求的Hello World。这个样本应用程序将帮助您设置 Node.js。

首先,让我们创建一个名为hello.js的样本应用程序:

1cd ~
2nano hello.js

将以下代码插入到文件中:

 1[label ~/hello.js]
 2const http = require('http');
 3
 4const hostname = 'localhost';
 5const port = 3000;
 6
 7const server = http.createServer((req, res) => {
 8  res.statusCode = 200;
 9  res.setHeader('Content-Type', 'text/plain');
10  res.end('Hello World!\n');
11});
12
13server.listen(port, hostname, () => {
14  console.log(`Server running at http://${hostname}:${port}/`);
15});

保存文件并离开编辑器。

这个 Node.js 应用程序在指定的地址(‘localhost’)和端口(‘3000’)上收听,并以‘200’ HTTP 成功代码返回Hello World! 因为我们正在收听‘localhost’,所以远程客户端将无法连接到我们的应用程序。

要测试您的应用程序,类型:

1node hello.js

您将获得以下输出:

1[secondary_label Output]
2Server running at http://localhost:3000/

<$>[注] 注: 以这种方式运行 Node.js 应用程序将阻止额外的命令,直到应用程序通过点击 CTRL+C 被杀死。

要测试该应用程序,请在您的服务器上打开另一个终端会话,并使用curl连接到localhost:

1[environment second]
2curl http://localhost:3000

如果您收到以下输出,应用程序正在正常工作,并在正确的地址和端口上收听:

1[secondary_label Output]
2[environment second]
3Hello World!

如果您无法获得预期的输出,请确保您的 Node.js 应用程序运行并配置为听取正确的地址和端口。

一旦你确定它工作,杀死应用程序(如果你还没有)通过按CTRL+C

步骤三:安装PM2

接下来,让我们安装 PM2,一个 Node.js 应用程序的流程管理器。

使用npm在您的服务器上安装最新版本的 PM2:

1sudo npm install pm2@latest -g

-g选项告诉npm安装模块 globally,以便它在整个系统中可用。

让我们先使用pm2 start命令在背景中运行您的应用程序hello.js:

1pm2 start hello.js

这还会将您的应用程序添加到 PM2 的流程列表中,该列表每次启动应用程序时都会输出:

 1[secondary_label Output]
 2...
 3[PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2
 4[PM2] PM2 Successfully daemonized
 5[PM2] Starting /home/sammy/hello.js in fork_mode (1 instance)
 6[PM2] Done.
 7┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐
 8│ id │ name               │ mode     │ ↺    │ status    │ cpu      │ memory   │
 9├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
10│ 0  │ hello              │ fork     │ 0    │ online    │ 0%       │ 25.2mb   │
11└────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘

如上所示,PM2 会自动分配一个应用名称(基于文件名,不含.js扩展)和一个 PM2 id。PM2 还保留了其他信息,如过程的PID,其当前状态和内存使用情况。

如果应用程序故障或被杀死,在PM2下运行的应用程序将自动重新启动,但我们可以采取额外的步骤,通过startup子命令将应用程序启动到系统启动上。

1pm2 startup systemd

结果输出的最后一行将包含一个命令以超级用户权限运行,以便设置PM2开始启动:

1[secondary_label Output]
2[PM2] Init System found: systemd
3sammy
4[PM2] To setup the Startup Script, copy/paste the following command:
5sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

从输出中运行命令,使用您的用户名代替sammy:

1sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy

作为一个额外的步骤,我们可以保存 PM2 流程列表和相应的环境:

1pm2 save

您现在已经创建了一个 systemd unit,该实例为您的启动用户运行pm2

使用systemctl开始服务:

1sudo systemctl start pm2-sammy

如果此时遇到错误,您可能需要重新启动,这可以通过突然重新启动来实现。

检查系统d 单元的状态:

1systemctl status pm2-sammy

有关 systemd 的详细概述,请参阅 Systemd Essentials: Working with Services, Units, and the Journal

除了我们所涵盖的,PM2还提供许多子命令,允许您管理或搜索有关您的应用程序的信息。

使用此命令停止应用程序(指定PM2应用程序名称id):

1pm2 stop app_name_or_id

重新启动应用程序:

1pm2 restart app_name_or_id

列出目前由 PM2 管理的应用程序:

1pm2 list

使用其应用名称获取有关特定应用程序的信息:

1pm2 info app_name

PM2 流程监视器可以通过monit子命令拉上,显示应用程序状态、CPU 和内存使用量:

1pm2 monit

请注意,在没有任何参数的情况下运行pm2也会显示有示例使用的帮助页面。

现在您的 Node.js 应用程序正在运行并由 PM2 管理,让我们设置反向代理。

步骤 4 — 将 Nginx 设置为反向代理服务器

您的应用程序正在运行并听到本地主机,但您需要为您的用户设置一种访问方式,我们将为此设置 Nginx 网页服务器作为反向代理。

在前提教程中,您将您的 Nginx 配置设置为 /etc/nginx/sites-available/example.com 文件。

1sudo nano /etc/nginx/sites-available/example.com

服务器区块中,你应该有一个现有的位置/区块,用以下配置来替换该区块的内容,如果你的应用程序设置为在不同的端口上收听,请将突出部分更新到正确的端口号:

 1[label /etc/nginx/sites-available/example.com]
 2server {
 3...
 4    location / {
 5        proxy_pass http://localhost:3000;
 6        proxy_http_version 1.1;
 7        proxy_set_header Upgrade $http_upgrade;
 8        proxy_set_header Connection 'upgrade';
 9        proxy_set_header Host $host;
10        proxy_cache_bypass $http_upgrade;
11    }
12...
13}

假设我们的服务器在example.com上可用,通过网页浏览器访问https://example.com/将请求发送到hello.js,在localhost端口3000上聆听。

您可以将额外的位置块添加到相同的服务器块中,以便提供在相同的服务器上其他应用程序的访问。例如,如果您也在端口3001上运行另一个 Node.js 应用程序,您可以添加此位置块,以便通过https://example.com/app2访问它:

 1[label /etc/nginx/sites-available/example.com — Optional]
 2server {
 3...
 4    location /app2 {
 5        proxy_pass http://localhost:3001;
 6        proxy_http_version 1.1;
 7        proxy_set_header Upgrade $http_upgrade;
 8        proxy_set_header Connection 'upgrade';
 9        proxy_set_header Host $host;
10        proxy_cache_bypass $http_upgrade;
11    }
12...
13}

完成为您的应用程序添加位置块后,保存文件并退出编辑器。

确保您没有输入任何语法错误,键入:

1sudo nginx -t

重新启动 Nginx:

1sudo systemctl restart nginx

假设您的 Node.js 应用程序正在运行,您的应用程序和 Nginx 配置是正确的,您现在应该能够通过 Nginx 反向代理程序访问您的应用程序。

结论

恭喜您!您现在有您的 Node.js 应用程序在 Ubuntu 20.04 服务器上运行 Nginx 反向代理程序后面。 此反向代理程序设置足够灵活,可让您的用户访问您想要共享的其他应用程序或静态 Web 内容。

Published At
Categories with 技术
comments powered by Disqus