15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用
09.10.2024

如何在Ubuntu上安装Node.js和PM2:完整生产环境指南

Node.js 是一个基于 Chrome V8 引擎构建的异步、事件驱动 JavaScript 运行时,专为在服务器端以高吞吐量执行 JavaScript 代码而设计。PM2 是一款面向生产环境的 Node.js 应用程序进程管理器,通过单一 CLI 界面提供守护进程化、自动崩溃恢复、日志聚合、集群模式负载均衡以及启动脚本生成等功能。

本指南涵盖在生产环境中于 Ubuntu 20.04、22.04 或 24.04 LTS 上可靠运行 Node.js 应用程序所需的每种安装方法、配置选项和操作模式。

前提条件

在继续之前,请确认以下内容:

  • 操作系统: Ubuntu 20.04、22.04 或 24.04 LTS(服务器或桌面版)
  • 用户权限: `sudo` 或 root 访问权限
  • 网络访问: 出站 HTTPS 以下载软件包和脚本
  • 已安装 curl: 如尚未安装,请运行 `sudo apt install curl -y`

如果您在云服务器上运行,VPS 托管环境是 Node.js 工作负载最常见的部署目标,本指南中的所有内容均可直接适用。

第一步:更新系统软件包

在安装新软件之前,请务必同步软件包索引并应用待处理的升级。过时的软件包元数据是依赖冲突的常见来源。

“`bash

sudo apt update

sudo apt upgrade -y

“`

升级完成后,如果内核已更新,请重启系统:

“`bash

sudo reboot

“`

第二步:安装 Node.js — 选择正确的方法

在 Ubuntu 上安装 Node.js 有三种主要方法。每种方法在版本控制、隔离性和系统范围可用性方面各有不同的权衡。

方法比较

功能NodeSource (apt)NVM系统 apt (universe)
版本控制单一固定主版本每用户多版本通常为过时的 LTS
系统范围安装否(默认按用户)
版本切换需要重新运行设置脚本`nvm use <version>`不支持
最适合CI/CD、单版本服务器开发、多项目仅用于快速测试
npm 全局包需要 sudo
生产适用性

方法一:通过 NodeSource 安装 Node.js(推荐用于服务器)

NodeSource 为每个活跃的 Node.js 发布线维护最新的 Debian/Ubuntu 软件仓库。这是生产服务器的首选方法,适用于需要系统范围内单一稳定版本的场景。

为当前 LTS 版本添加 NodeSource 软件仓库:

“`bash

curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash –

“`

该脚本执行以下几项操作:检测您的 Ubuntu 版本、添加相应的 NodeSource apt 软件仓库、导入 GPG 签名密钥,并运行 `apt-get update`。`-E` 标志在提升至 sudo 时保留您的环境变量,如果您配置了代理设置,这一点尤为重要。

安装 Node.js 和 npm:

“`bash

sudo apt install nodejs -y

“`

NodeSource 软件包将 `node` 和 `npm` 捆绑在单个 `nodejs` 软件包中。与 Ubuntu universe 软件包不同,它不会将两者分开。

验证安装:

“`bash

node -v

npm -v

“`

预期输出示例:

“`

v20.14.0

10.7.0

“`

固定到特定主版本:如果您需要 Node.js 18 而非当前 LTS,请在 curl 命令中将 `setup_lts.x` 替换为 `setup_18.x`。可用的版本流包括 `setup_18.x`、`setup_20.x` 和 `setup_22.x`。

方法二:通过 NVM 安装 Node.js(推荐用于开发和多版本环境)

NVM(Node 版本管理器)将 Node.js 安装到您的主目录中,无需 root 权限即可安装 Node.js 本身或全局 npm 软件包。这消除了在系统安装的 Node.js 上运行 `npm install -g` 时常见的权限问题。

安装 NVM:

“`bash

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash

“`

在运行此命令之前,请检查官方 NVM 仓库以获取最新的发布标签——URL 中的版本号会随每次发布而变化。

重新加载 shell 环境:

“`bash

source ~/.bashrc

“`

如果您使用 Zsh,请改为 source `~/.zshrc`。NVM 安装程序会将其初始化块追加到它检测到的 shell 配置文件中。

安装最新的 LTS 版本 Node.js:

“`bash

nvm install –lts

“`

在 LTS 旁边安装特定版本:

“`bash

nvm install 18

nvm install 20

“`

在已安装版本之间切换:

“`bash

nvm use 20

nvm alias default 20

“`

`alias default` 命令设置在新 shell 会话中激活的版本,这对于不加载交互式 shell 配置文件的脚本和 cron 任务至关重要。

验证:

“`bash

node -v

npm -v

“`

NVM 在生产环境中的关键陷阱:由于 NVM 是用户范围的,PM2 的启动脚本和 systemd 单元将无法访问 NVM 管理的 Node.js 二进制文件,除非您明确配置路径。请参阅第五步了解如何正确处理此问题。

第三步:安装 PM2

PM2 作为 npm 软件包分发,应全局安装以使其 CLI 在系统范围内可用。

安装 PM2:

“`bash

sudo npm install -g pm2

“`

如果您通过 NVM 安装了 Node.js,请省略 `sudo`:

“`bash

npm install -g pm2

“`

验证安装:

“`bash

pm2 -v

“`

安装特定 PM2 版本(在固定基础设施时很有用):

“`bash

sudo npm install -g pm2@5.3.1

“`

PM2 5.x 版本是当前稳定版本线。与 v4 相比,它对 Web 仪表板(pm2 plus)、日志轮转和模块系统进行了重大改进。

第四步:使用 PM2 管理 Node.js 应用程序

启动应用程序

导航到您的应用程序目录并启动它:

“`bash

cd /var/www/my-app

pm2 start app.js –name "my-app"

“`

始终指定 `–name` 标志。如果没有它,PM2 会使用文件名作为进程名称,当您有多个服务时会产生歧义。

使用附加选项启动:

“`bash

pm2 start app.js –name "my-app" –watch –max-memory-restart 300M

“`

  • `–watch`:当源文件发生变化时重启进程(在预发布环境中有用,不建议在生产环境中使用)
  • `–max-memory-restart 300M`:如果进程超过 300 MB RSS 内存,则自动重启——这是防止内存泄漏的关键保障措施

查看运行中的进程

“`bash

pm2 list

“`

这将输出一个表格,显示进程 ID、名称、模式(fork/cluster)、PID、状态、CPU 使用率、内存消耗和重启次数。

实时仪表板:

“`bash

pm2 monit

“`

控制进程

“`bash

pm2 restart my-app # Graceful restart

pm2 reload my-app # Zero-downtime reload (cluster mode only)

pm2 stop my-app # Stop without removing from process list

pm2 delete my-app # Stop and remove from process list

“`

`restart` 与 `reload` 的区别:`restart` 会终止进程并启动新进程,导致短暂停机。`reload`(仅在集群模式下可用)逐个循环工作进程,在整个过程中保持可用性。在生产集群部署中始终使用 `reload`。

日志管理

“`bash

pm2 logs # Stream logs from all processes

pm2 logs my-app # Stream logs for a specific process

pm2 logs my-app –lines 200 # Show last 200 lines

pm2 flush # Clear all log files

“`

PM2 默认将日志存储在 `~/.pm2/logs/`。对于生产服务器,请安装日志轮转模块以防止磁盘耗尽:

“`bash

pm2 install pm2-logrotate

pm2 set pm2-logrotate:max_size 50M

pm2 set pm2-logrotate:retain 10

pm2 set pm2-logrotate:compress true

“`

这会在日志达到 50 MB 时进行轮转,保留 10 个压缩归档,并防止日志无限增长——这是长期运行服务器上的常见问题,通常在磁盘空间耗尽之前都被忽视。

第五步:配置 PM2 在系统启动时运行

必须将 PM2 配置为在服务器重启后继续运行。这通过由 PM2 自身生成的 systemd 服务单元来处理。

生成启动命令:

“`bash

pm2 startup

“`

PM2 将输出一个针对您的 init 系统和当前用户定制的命令,如下所示:

“`

[PM2] Init System found: systemd

[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 ubuntu –hp /home/ubuntu

“`

复制并执行该确切命令。请勿修改它——PM2 二进制文件的路径和主目录必须与您系统的配置匹配。

NVM 特定的启动配置:如果您通过 NVM 安装了 Node.js,生成命令中的路径将指向您的 NVM 管理的二进制文件。这是正确的,但您必须在运行 `pm2 startup` 之前确保将 NVM 版本设置为默认版本:

“`bash

nvm alias default 20

pm2 startup

“`

保存当前进程列表:

“`bash

pm2 save

“`

这会将进程列表写入 `~/.pm2/dump.pm2`。重启时,systemd 单元读取此文件并恢复所有已保存的进程。如果您之后添加或删除应用程序,请再次运行 `pm2 save` 以更新快照。

验证 systemd 单元是否处于活动状态:

“`bash

systemctl status pm2-ubuntu

“`

将 `ubuntu` 替换为您的实际用户名。

第六步:使用 PM2 生态系统文件进行生产部署

对于超出单脚本应用程序的任何情况,请使用 PM2 的生态系统配置文件。它提供可重现的、版本控制的进程定义,并消除了记忆冗长 CLI 标志的需要。

生成生态系统文件

“`bash

pm2 ecosystem

“`

这会在当前目录中创建 `ecosystem.config.js`。

生产就绪的生态系统配置

“`javascript

module.exports = {

apps: [

{

name: 'api-server',

script: './src/server.js',

instances: 'max',

exec_mode: 'cluster',

watch: false,

max_memory_restart: '500M',

log_date_format: 'YYYY-MM-DD HH:mm:ss Z',

error_file: '/var/log/pm2/api-server-error.log',

out_file: '/var/log/pm2/api-server-out.log',

merge_logs: true,

env: {

NODE_ENV: 'development',

PORT: 3000

},

env_production: {

NODE_ENV: 'production',

PORT: 8080

}

},

{

name: 'worker',

script: './src/worker.js',

instances: 2,

exec_mode: 'fork',

cron_restart: '0 2 * * *',

env_production: {

NODE_ENV: 'production'

}

}

]

};

“`

关键配置决策说明:

  • `instances: 'max'`:PM2 自动为每个逻辑 CPU 核心生成一个工作进程。在 4 核服务器上,这将创建 4 个 Node.js 进程,充分利用硬件资源。
  • `exec_mode: 'cluster'`:使用 Node.js 内置的集群模块。所有实例通过操作系统的套接字负载均衡共享同一端口。
  • `exec_mode: 'fork'`:将进程作为独立子进程运行。对于非 HTTP 服务器的应用程序(队列工作进程、定时任务、具有粘性会话的 WebSocket 服务器)是必需的。
  • `merge_logs: true`:将所有集群实例的标准输出合并到单个日志文件中,使日志分析更加简便。
  • `cron_restart`:使用 cron 语法安排自动重启。适用于积累状态的工作进程或应用夜间配置更改。

使用生态系统文件启动

“`bash

pm2 start ecosystem.config.js –env production

pm2 save

“`

零停机部署工作流

部署应用程序新版本时:

“`bash

git pull origin main

npm install –production

pm2 reload ecosystem.config.js –env production

“`

`pm2 reload` 逐个向每个工作进程发送 `SIGINT`,等待新工作进程就绪,然后终止旧进程。您的应用程序必须优雅地处理 `SIGINT`,并使用 `process.send('ready')` 发出就绪信号,这样才能正常工作。

应用程序中的优雅关闭处理程序:

“`javascript

process.on('SIGINT', () => {

server.close(() => {

console.log('HTTP server closed');

process.exit(0);

});

});

“`

第七步:PM2 监控与可观测性

内置监控

“`bash

pm2 monit

“`

在终端中显示每个进程的实时 CPU 和内存图表。

进程信息

“`bash

pm2 show my-app

“`

输出详细元数据:运行时间、重启次数、版本信息、解释器路径、环境变量和日志文件位置。

PM2 Web 仪表板(PM2 Plus)

PM2 在 pm2.io 提供托管监控仪表板。连接您的服务器:

“`bash

pm2 link <secret_key> <public_key>

“`

这提供历史指标、告警和远程进程管理——在管理多台服务器或需要在没有 SSH 访问权限的情况下获得可见性时尤为有价值。

第八步:更新 Node.js 和 PM2

更新 PM2

“`bash

sudo npm install -g pm2@latest

pm2 update

“`

升级 PM2 二进制文件后,`pm2 update` 是必不可少的——它在不中断运行进程的情况下更新内存中的 PM2 守护进程。

通过 NodeSource 更新 Node.js

为新主版本重新运行设置脚本:

“`bash

curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash –

sudo apt install nodejs -y

“`

更新 Node.js 后,重启 PM2 以确保它使用新的二进制文件:

“`bash

pm2 restart all

“`

通过 NVM 更新 Node.js

“`bash

nvm install 22

nvm alias default 22

nvm use 22

pm2 restart all

“`

如果您更改了默认 NVM 版本,请重新生成 PM2 启动脚本以更新 systemd 单元中的二进制文件路径:

“`bash

pm2 unstartup

pm2 startup

pm2 save

“`

安全加固注意事项

在生产环境中运行 Node.js 应用程序需要关注进程管理之外的事项:

  • 以非 root 用户运行:切勿以 root 身份运行 PM2 或 Node.js。创建专用系统用户(`adduser –system –group nodeapp`)并在该账户下运行 PM2。
  • 环境变量管理:不要在 `ecosystem.config.js` 中硬编码密钥。使用通过 `dotenv` 加载的 `.env` 文件,或通过部署管道注入密钥。生态系统文件通常会提交到版本控制系统。
  • 反向代理:在 Node.js 应用程序前面放置 Nginx 或 Caddy。这处理 TLS 终止、静态文件服务、速率限制和请求缓冲。配合SSL 证书解决方案以强制执行 HTTPS。
  • 防火墙规则:阻止从公共互联网直接访问您的 Node.js 端口(例如 3000、8080)。只有反向代理应与 Node.js 通信。
  • 资源限制:在 PM2 中设置 `max_memory_restart`,并配置系统级 `ulimit` 值,以防止单个失控进程破坏服务器稳定性。

对于资源隔离至关重要的高流量生产部署,独立服务器环境提供完整的硬件控制,并消除了共享基础设施固有的”嘈杂邻居”问题。

为 Node.js 选择合适的托管环境

工作负载推荐环境理由
个人项目、预发布环境[VPS 托管](https://alexhost.com/zh/vps/)性价比高、完整 root 访问权限、可扩展
高流量 API[独立服务器](https://alexhost.com/zh/dedicated-servers/)性能可预测,无资源争用
ML 推理 + Node.js[GPU 托管](https://alexhost.com/zh/gpu-hosting/)将计算密集型任务卸载到 GPU 工作进程
托管控制面板[带 cPanel 的 VPS](https://alexhost.com/zh/vps/control-panels/cpanel-vps/)基于 GUI 的进程和文件管理

技术决策检查清单

在将 Node.js 和 PM2 部署到生产环境之前,请使用此检查清单:

  • [ ] Node.js 通过 NodeSource(服务器)或 NVM(开发)安装——而非 Ubuntu universe 软件包
  • [ ] PM2 以正确权限全局安装,适配您的安装方法
  • [ ] 应用程序以 `–name` 标志启动并定义了 `–max-memory-restart` 阈值
  • [ ] HTTP 服务器启用集群模式;后台工作进程使用 fork 模式
  • [ ] 已执行 `pm2 startup` 并使用 sudo 运行生成的命令
  • [ ] 所有进程配置完成后运行 `pm2 save`
  • [ ] 已安装并配置日志轮转模块
  • [ ] Nginx 或 Caddy 已配置为带 TLS 的反向代理
  • [ ] 应用程序优雅处理 `SIGINT` 以实现零停机重载
  • [ ] 密钥在 `ecosystem.config.js` 之外管理
  • [ ] 已通过 `systemctl status pm2-<username>` 验证 PM2 systemd 单元
  • [ ] 防火墙阻止从公共互联网直接访问 Node.js 端口

常见问题

PM2 fork 模式和集群模式有什么区别?

Fork 模式将应用程序作为单个子进程生成——一个实例,利用一个 CPU 核心。集群模式使用 Node.js 的原生集群模块生成多个工作进程,这些进程共享同一 TCP 端口,实现真正的多核利用和零停机重载。对 HTTP/HTTPS 服务器使用集群模式,对工作进程、cron 任务或维护与多进程共享不兼容的内部状态的应用程序使用 fork 模式。

为什么即使运行了 `pm2 startup`,PM2 在服务器重启后也不会重启?

最常见的原因是在配置进程后没有运行 `pm2 save`,导致转储文件为空或缺失。第二个最常见的原因是 NVM 路径不匹配:如果在生成启动脚本后更改了 NVM 默认版本,systemd 单元会指向不存在的二进制文件。解决方法是运行 `pm2 unstartup`,设置正确的 NVM 默认版本,然后重新运行 `pm2 startup` 和 `pm2 save`。

PM2 可以管理非 Node.js 进程吗?

可以。PM2 可以通过指定解释器来管理任何可执行文件。例如:`pm2 start script.py –interpreter python3`。这使 PM2 可作为混合语言微服务架构的通用进程监督器。

如何在单台服务器后面的不同端口上运行多个 Node.js 应用程序?

在 `ecosystem.config.js` 中将每个应用程序定义为单独的条目,并使用不同的 `PORT` 环境变量。将 Nginx 配置为反向代理,使用单独的 `server` 块或 `location` 指令路由到每个端口。所有应用程序共享同一个 PM2 守护进程,并通过单个 `pm2 list` 视图进行管理。

对于生产 VPS,我应该使用 NVM 还是 NodeSource?

NodeSource 通常更适合生产服务器。它将 Node.js 作为系统软件包安装,使其对所有用户和系统服务可用,无需 shell 初始化依赖。NVM 的按用户、按 shell 激活模型在 systemd 单元、cron 任务以及在交互式 shell 会话之外运行的 CI/CD 管道中会引入微妙的故障模式。将 NVM 保留用于本地开发机器,在那里同时管理多个 Node.js 版本是真正的需求。

15%

全场主机优惠15%

测试技能,享折扣

使用代码:

Skills
开始使用