如何在Ubuntu16.04上设置用于生产的Node.js应用程序
介绍
Node.js 是用于构建服务器端和网络应用程序的开源 JavaScript 运行时环境。 该平台在 Linux、MacOS、FreeBSD 和 Windows 上运行。 Node.js 应用程序可以在命令行中运行,但我们将专注于将它们作为服务运行,以便它们在重启或故障时自动重启,并且可以安全地用于生产环境。
在本教程中,我们将介绍在单个 Ubuntu 16.04 服务器上设置生产就绪的 Node.js 环境。 该服务器将运行由 PM2 管理的 Node.js 应用程序,并通过 Nginx 反向代理为用户提供对应用程序的安全访问。 Nginx 服务器将使用 Let's Encrypt 提供的免费证书提供 HTTPS。
先决条件
本指南假定您具备以下条件:
- Ubuntu 16.04 服务器,配置有具有
sudo
权限的非 root 用户,如 Ubuntu 16.04 的 初始服务器设置指南中所述。 - 根据 How to Set Up a Host Name with DigitalOcean 的域名指向您服务器的公共 IP。 本教程将自始至终使用 example.com。
- 已安装 Nginx,在 How To Install Nginx on Ubuntu 16.04 中有介绍
- Nginx 使用 Let's Encrypt 证书配置了 SSL。 如何在 Ubuntu 16.04 上使用 Let's Encrypt 保护 Nginx 将引导您完成整个过程。
完成先决条件后,您将拥有一个服务器,该服务器在 https://example.com/ 处为默认的 Nginx 占位符页面提供服务。
让我们开始在您的服务器上安装 Node.js 运行时。
第 1 步 — 安装 Node.js
我们将使用 NodeSource 包档案安装最新的 LTS 版本的 Node.js。
首先,您需要安装 NodeSource PPA 才能访问其内容。 确保您位于主目录中,并使用 curl
检索 Node.js 16.x 档案的安装脚本:
cd ~ curl -sL https://deb.nodesource.com/setup_16.x -o nodesource_setup.sh
您可以使用 nano
(或您喜欢的文本编辑器)检查此脚本的内容:
nano nodesource_setup.sh
然后在sudo
下运行脚本:
sudo bash nodesource_setup.sh
PPA 将添加到您的配置中,并且您的本地包缓存将自动更新。 从 nodesource 运行安装脚本后,您可以按照与上面相同的方式安装 Node.js 包:
sudo apt-get install nodejs
nodejs
软件包包含 node
二进制文件以及 npm
,因此您无需单独安装 npm
。 但是,为了使某些 npm
包能够工作(例如那些需要从源代码编译代码的包),您需要安装 build-essential
包:
sudo apt-get install build-essential
Node.js 运行时现已安装,并准备好运行应用程序。 让我们编写一个 Node.js 应用程序。
第 2 步 — 创建 Node.js 应用程序
我们将编写一个 Hello World 应用程序,它会向任何 HTTP 请求返回“Hello World”。 这是一个示例应用程序,可帮助您设置 Node.js,您可以将其替换为您自己的应用程序 — 只需确保修改您的应用程序以侦听适当的 IP 地址和端口。
你好世界代码
首先,创建并打开您的 Node.js 应用程序进行编辑。 在本教程中,我们将使用 nano
编辑一个名为 hello.js
的示例应用程序:
cd ~ nano hello.js
将以下代码插入文件中。 如果您愿意,您可以在两个位置替换突出显示的端口 8080
(请务必使用非管理员端口,即 1024 或更高):
你好.js
#!/usr/bin/env nodejs var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello World\n'); }).listen(8080, 'localhost'); console.log('Server running at http://localhost:8080/');
现在保存并退出。
此 Node.js 应用程序侦听指定的地址 (localhost
) 和端口 (8080
),并返回带有 200
HTTP 成功代码的“Hello World”。 由于我们正在侦听 localhost,远程客户端将无法连接到我们的应用程序。
测试申请
为了测试您的应用程序,使用 chmod
将 hello.js
设置为可执行:
chmod +x ./hello.js
然后像这样运行它:
./hello.js
OutputServer running at http://localhost:8080/
注意: 以这种方式运行 Node.js 应用程序将阻止其他命令,直到应用程序被按 Ctrl-C 杀死。
为了测试应用程序,在您的服务器上打开另一个终端会话,并使用 curl
连接到 localhost:
curl http://localhost:8080
如果您看到以下输出,则表明应用程序正常工作并正在侦听正确的地址和端口:
OutputHello World
如果您没有看到正确的输出,请确保您的 Node.js 应用程序正在运行,并配置为侦听正确的地址和端口。
一旦你确定它工作正常,切换回你的另一个终端并通过按 Ctrl+C 来终止 Node.js 应用程序(如果你还没有)。
第 3 步 — 安装 PM2
现在我们将安装 PM2,它是 Node.js 应用程序的进程管理器。 PM2 提供了一种简单的方法来管理和守护应用程序(将它们作为服务在后台运行)。
我们将使用 npm
,一个用于安装 Node.js 的 Node 模块的包管理器,在我们的服务器上安装 PM2。 使用此命令安装 PM2:
sudo npm install -g pm2
-g
选项告诉 npm
安装模块 globally,以便它在系统范围内可用。
第 4 步 — 使用 PM2 管理应用程序
我们将介绍 PM2 的一些基本用途。
开始申请
您要做的第一件事是使用 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 │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ hello │ default │ N/A │ fork │ 13734 │ 0s │ 0 │ online │ 0% │ 25.0mb │ sammy │ disabled │ └─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘
如您所见,PM2 自动分配一个 name(基于文件名,没有 .js
扩展名)和一个 PM2 id。 PM2 还维护其他信息,例如进程的PID、当前状态和内存使用情况。
如果应用程序崩溃或被杀死,在 PM2 下运行的应用程序将自动重新启动,但需要采取额外的步骤来使应用程序在系统启动(启动或重新启动)时启动。 幸运的是,PM2 提供了一种简单的方法来执行此操作,即 startup
子命令。
startup
子命令生成并配置启动脚本以在服务器启动时启动 PM2 及其托管进程:
pm2 startup systemd
结果输出的最后一行将包含一个您必须以超级用户权限运行的命令:
Output[PM2] Init System found: systemd [PM2] You have to run this command as root. Execute the following command: sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
运行生成的命令(类似于上面突出显示的输出,但使用您的用户名而不是 sammy
)将 PM2 设置为在启动时启动(使用您自己输出中的命令):
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u sammy --hp /home/sammy
这将创建一个 systemd unit,它会在启动时为您的用户运行 pm2
。 这个 pm2
实例依次运行 hello.js
。 您可以使用 systemctl
检查 systemd 单元的状态:
systemctl status pm2-sammy
有关 systemd 的详细概述,请参阅 Systemd Essentials: Working with Services, Units, and the Journal 。
其他 PM2 用途(可选)
PM2 提供了许多子命令,允许您管理或查找有关应用程序的信息。 请注意,不带任何参数运行 pm2
将显示一个帮助页面,包括示例用法,它比本教程的这一部分更详细地介绍了 PM2 的用法。
使用此命令停止应用程序(指定 PM2 App name
或 id
):
pm2 stop app_name_or_id
使用此命令重新启动应用程序(指定 PM2 App name
或 id
):
pm2 restart app_name_or_id
当前由 PM2 管理的应用程序列表也可以使用 list
子命令查找:
pm2 list
可以使用 info
子命令找到有关特定应用程序的更多信息(指定 PM2 App name 或 id):
pm2 info example
PM2 过程监视器可以使用 monit
子命令启动。 这将显示应用程序状态、CPU 和内存使用情况:
pm2 monit
现在您的 Node.js 应用程序正在运行并由 PM2 管理,让我们设置反向代理。
第 5 步 — 将 Nginx 设置为反向代理服务器
现在您的应用程序正在运行,并且正在侦听 localhost,您需要为您的用户设置一种访问它的方式。 为此,我们将 Nginx Web 服务器设置为反向代理。
在先决条件教程中,我们在 /etc/nginx/sites-available/default
文件中设置了 Nginx 配置。 打开文件进行编辑:
sudo nano /etc/nginx/sites-available/default
在 server
块中,您应该有一个现有的 location /
块。 将该块的内容替换为以下配置。 如果您的应用程序设置为侦听不同的端口,请将突出显示的部分更新为正确的端口号。
/etc/nginx/sites-available/default
. . . location / { proxy_pass http://localhost:8080; 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; } }
这将服务器配置为响应其根的请求。 假设我们的服务器在 example.com
可用,通过 Web 浏览器访问 https://example.com/
会将请求发送到 hello.js
,监听 localhost 的端口 8080
。
您可以将额外的 location
块添加到同一服务器块,以提供对同一服务器上其他应用程序的访问。 例如,如果您还在端口 8081
上运行另一个 Node.js 应用程序,则可以添加此位置块以允许通过 http://example.com/app2
访问它:
/etc/nginx/sites-available/default — 可选
location /app2 { proxy_pass http://localhost:8081; 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 地址或域名)进行尝试。
结论
恭喜! 现在,您的 Node.js 应用程序在 Ubuntu 16.04 服务器上的 Nginx 反向代理后面运行。 这种反向代理设置足够灵活,可以让您的用户访问您想要共享的其他应用程序或静态 Web 内容。 祝您的 Node.js 开发顺利。