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

本教程指导在Ubuntu20.04服务器上设置生产就绪的Node.js环境,包括使用PM2管理应用,通过Nginx实现HTTPS反向代理。首先安装Node.js和npm,接着创建一个简单的'HelloWorld'应用,然后使用PM2作为进程管理器确保应用在后台稳定运行。最后,配置Nginx作为反向代理,使用户能通过HTTPS安全访问应用程序。
摘要由CSDN通过智能技术生成

介绍

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

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

首先,安装 NodeSource PPA 以访问其内容。确保您位于您的主目录中,并使用curl它从其存档中检索最新 LTS 版本的 Node.js 的安装脚本。

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

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

 
 
  1. nano nodesource_setup.sh
复制

检查完脚本后,在下面运行它sudo

 
 
  1. sudo bash nodesource_setup.sh
复制

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

 
 
  1. sudo apt install nodejs
复制

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

 
 
  1. node -v
复制
 
Output

v14.4.0

注意:从 NodeSource PPA 安装时,Node.js 可执行文件称为nodejs,而不是node.

nodejs包包含nodejs二进制文件以及npmNode 模块的包管理器,因此您无需npm单独安装。

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

 
 
  1. npm -v
复制
 
Output

6.14.5

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

 
 
  1. sudo apt install build-essential
复制

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

安装了 Node.js 运行时后,让我们继续编写 Node.js 应用程序。

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

让我们编写一个向任何 HTTP 请求返回“Hello World”的Hello World应用程序。此示例应用程序将帮助您设置 Node.js。您可以将其替换为您自己的应用程序 — 只需确保修改您的应用程序以侦听适当的 IP 地址和端口。

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

 
 
  1. cd ~
  2. nano hello.js
复制

在文件中插入以下代码:

~/hello.js
<span style="color:#000000"><span style="background-color:#f3f5f9"><span style="color:#535772"><code class="language-javascript"><span style="color:#0069ff">const</span> http <span style="color:#666a71">=</span> <span style="color:#e0276a">require</span><span style="color:#666a71">(</span><span style="color:#08966b">'http'</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>

<span style="color:#0069ff">const</span> hostname <span style="color:#666a71">=</span> <span style="color:#08966b">'localhost'</span><span style="color:#666a71">;</span>
<span style="color:#0069ff">const</span> port <span style="color:#666a71">=</span> <span style="color:#225196">3000</span><span style="color:#666a71">;</span>

<span style="color:#0069ff">const</span> server <span style="color:#666a71">=</span> http<span style="color:#666a71">.</span><span style="color:#e0276a">createServer</span><span style="color:#666a71">(</span><span style="color:#666a71">(</span>req<span style="color:#666a71">,</span> res<span style="color:#666a71">)</span> <span style="color:#666a71">=></span> <span style="color:#666a71">{</span>
  res<span style="color:#666a71">.</span>statusCode <span style="color:#666a71">=</span> <span style="color:#225196">200</span><span style="color:#666a71">;</span>
  res<span style="color:#666a71">.</span><span style="color:#e0276a">setHeader</span><span style="color:#666a71">(</span><span style="color:#08966b">'Content-Type'</span><span style="color:#666a71">,</span> <span style="color:#08966b">'text/plain'</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>
  res<span style="color:#666a71">.</span><span style="color:#e0276a">end</span><span style="color:#666a71">(</span><span style="color:#08966b">'Hello World!\n'</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>
<span style="color:#666a71">}</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>

server<span style="color:#666a71">.</span><span style="color:#e0276a">listen</span><span style="color:#666a71">(</span>port<span style="color:#666a71">,</span> hostname<span style="color:#666a71">,</span> <span style="color:#666a71">(</span><span style="color:#666a71">)</span> <span style="color:#666a71">=></span> <span style="color:#666a71">{</span>
  console<span style="color:#666a71">.</span><span style="color:#e0276a">log</span><span style="color:#666a71">(</span><span style="color:#08966b">`</span><span style="color:#08966b">Server running at http://</span><span style="color:#666a71">${</span>hostname<span style="color:#666a71">}</span><span style="color:#08966b">:</span><span style="color:#666a71">${</span>port<span style="color:#666a71">}</span><span style="color:#08966b">/</span><span style="color:#08966b">`</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>
<span style="color:#666a71">}</span><span style="color:#666a71">)</span><span style="color:#666a71">;</span>
</code></span></span></span>
复制

保存文件并退出编辑器。

此 Node.js 应用程序侦听指定的地址 ( localhost) 和端口 ( 3000),并返回“Hello World!” 带有200HTTP 成功代码。由于我们正在监听localhost,远程客户端将无法连接到我们的应用程序。

要测试您的应用程序,请键入:

 
 
  1. node hello.js
复制

您将收到以下输出:

 
Output

Server running at http://localhost:3000/

注意:以这种方式运行 Node.js 应用程序将阻止其他命令,直到应用程序被按 终止CTRL+C

要测试应用程序,请在您的服务器上打开另一个终端会话,然后连接localhostcurl

 
 
  1. curl http://localhost:3000
复制

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

 
Output

Hello World!

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

一旦您确定它正在工作,请按 终止应用程序(如果您还没有)CTRL+C

第 3 步 — 安装 PM2

接下来让我们安装 PM2,一个 Node.js 应用程序的进程管理器。PM2 使守护应用程序成为可能,以便它们作为服务在后台运行。

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

 
 
  1. sudo npm install pm2@latest -g
复制

-g选项告诉全局npm安装模块,以便它在系统范围内可用。

让我们首先使用pm2 start命令hello.js在后台运行您的应用程序:

 
 
  1. 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 自动分配一个App name(基于文件名,不带.js扩展名)和一个 PM2 id。PM2 还维护其他信息,例如PID进程的名称、当前状态和内存使用情况。

如果应用程序崩溃或被杀死,在 PM2 下运行的应用程序将自动重新启动,但我们可以采取额外的步骤让应用程序在系统启动时使用startup子命令启动。此子命令生成并配置启动脚本以在服务器启动时启动 PM2 及其托管进程:

 
 
  1. pm2 startup systemd
复制

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

 
Output

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

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

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

作为附加步骤,我们可以保存 PM2 进程列表和相应的环境:

 
 
  1. pm2 save
复制

您现在已经创建了一个在启动时为您的用户运行的 systemd单元。反过来,pm2此实例运行.pm2hello.js

使用以下命令启动服务systemctl

 
 
  1. sudo systemctl start pm2-sammy
复制

如果此时您遇到错误,您可能需要重新启动,您可以使用sudo reboot.

检查 systemd 单元的状态:

 
 
  1. systemctl status pm2-sammy
复制

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

除了我们已经介绍的那些之外,PM2 还提供了许多子命令,允许您管理或查找有关您的应用程序的信息。

使用此命令停止应用程序(指定 PM2App nameid):

 
 
  1. pm2 stop app_name_or_id
复制

重新启动应用程序:

 
 
  1. pm2 restart app_name_or_id
复制

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

 
 
  1. pm2 list
复制

使用其获取有关特定应用程序的信息App name

 
 
  1. pm2 info app_name
复制

PM2 过程监视器可以使用monit子命令启动。这将显示应用程序状态、CPU 和内存使用情况:

 
 
  1. pm2 monit
复制

请注意,pm2不带任何参数运行也将显示带有示例用法的帮助页面。

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

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

您的应用程序正在运行并正在侦听localhost,但您需要设置一种方式让您的用户访问它。为此,我们将 Nginx Web 服务器设置为反向代理。

在先决条件教程中,您在文件中设置了 Nginx 配置。打开此文件进行编辑:/etc/nginx/sites-available/example.com

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

server块内,您​​应该有一个现有的location /块。将该块的内容替换为以下配置。如果您的应用程序设置为侦听不同的端口,请将突出显示的部分更新为正确的端口号:

/etc/nginx/sites-available/example.com
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;
    }
...
}

这将服务器配置为响应其根的请求。假设我们的服务器在 at 可用example.com,通过 Web 浏览器访问会将请求发送到,侦听at的端口。https://example.com/hello.js3000localhost

您可以向同一服务器块添加其他location块,以提供对同一服务器上其他应用程序的访问。例如,如果您还在 port 上运行另一个 Node.js 应用程序3001,您可以添加此位置块以允许通过以下方式访问它:https://example.com/app2

/etc/nginx/sites-available/example.com — 可选
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;
    }
...
}

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

确保您没有通过键入以下内容引入任何语法错误:

 
 
  1. sudo nginx -t
复制

重启 Nginx:

 
 
  1. sudo systemctl restart nginx
复制

假设您的 Node.js 应用程序正在运行,并且您的应用程序和 Nginx 配置正确,您现在应该能够通过 Nginx 反向代理访问您的应用程序。通过访问您的服务器的 URL(其公共 IP 地址或域名)来尝试一下。

结论

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值