如何在 Ubuntu 上安装 NVM for Node.js:完整技术指南
NVM (Node Version Manager) 是一个符合 POSIX 标准的 shell 脚本,可在单台机器上安装和管理多个独立的 Node.js 运行环境,无需 root 权限或修改系统级路径。每个 Node.js 版本都存放在 `~/.nvm/versions/node/` 下的独立目录中,为各项目提供完全无冲突的隔离环境。
本指南介绍如何在 Ubuntu(20.04、22.04 和 24.04)上进行生产级 NVM 安装,不仅涵盖基本命令,还包括 shell 配置文件的边缘情况、`.nvmrc` 工作流自动化、全局包迁移以及大多数教程所忽略的服务器特定问题。
为何选择 NVM 而非系统包管理器
通过 `apt` 安装 Node.js 会在 `/usr/bin/node` 放置一个系统级的单一二进制文件。升级它会同时影响主机上的每个应用程序。在共享开发机器或运行多个 Node.js 项目的 VPS 上,这会造成脆弱且难以复现的环境。
NVM 通过将每个 Node.js 版本安装到用户空间目录并在 shell 级别操控 `PATH` 来解决这一问题。其结果是实现按用户、按项目的版本控制,对操作系统的包状态零影响。
NVM 与其他 Node.js 版本管理器的对比
| 功能 | NVM | fnm | Volta | n |
|---|
| — | — | — | — | — |
|---|
| 语言 | Shell (Bash/Zsh) | Rust | Rust | Shell |
|---|
| 速度 | 中等 | 非常快 | 非常快 | 快 |
|---|
| `.nvmrc` 支持 | 是 | 是 | 部分支持 | 否 |
|---|
| 按项目锁定版本 | 是 | 是 | 是 | 否 |
|---|
| Windows 支持 | 否(仅 WSL) | 是 | 是 | 否 |
|---|
| 全局包隔离 | 是 | 是 | 是 | 否 |
|---|
| Shell 启动开销 | ~70ms | ~5ms | ~5ms | 极小 |
|---|
| 成熟度 / 生态系统 | 最高 | 高 | 中等 | 高 |
|---|
NVM 仍然是文档最完善、生态系统支持最广泛的选项,对于可复现性比原始启动速度更重要的团队和服务器环境而言,是最安全的默认选择。
前提条件
- Ubuntu 20.04、22.04 或 24.04(桌面版或服务器版)
- 具有 `sudo` 权限的非 root 用户账户
- 已安装 `curl` 或 `wget`(大多数 Ubuntu 镜像默认已包含)
- 具备 Bash 或 Zsh 的基本使用知识
在开始之前,确认您的 shell 和 Ubuntu 版本:
“`bash
echo $SHELL
lsb_release -a
“`
步骤 1:更新系统包索引
刷新 APT 包列表,确保本次会话中解析的所有依赖项均为最新版本:
“`bash
sudo apt-get update && sudo apt-get upgrade -y
“`
同时确认 `curl` 可用:
“`bash
curl –version || sudo apt-get install -y curl
“`
步骤 2:下载并运行 NVM 安装脚本
官方 NVM 安装程序托管在 GitHub 上。它会将 NVM 仓库克隆到 `~/.nvm`,并将必要的 shell 初始化块追加到您的配置文件中。
选项 A — 使用 curl(推荐):
“`bash
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
“`
选项 B — 使用 wget:
“`bash
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
“`
运行前请务必在 NVM GitHub 发布页面上核实最新的发布标签。如果已发布更新的稳定版本,请将 `v0.40.1` 替换为当前稳定标签。
安装程序实际执行的操作:
- 将 NVM 仓库克隆到 `~/.nvm`
- 检测您当前使用的 shell(`bash`、`zsh`、`ksh` 或 `fish`)
- 将以下初始化块追加到相应的配置文件中(`~/.bashrc`、`~/.zshrc`、`~/.profile` 或 `~/.bash_profile`)
“`bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && . "$NVM_DIR/bash_completion"
“`
安全提示:将远程脚本直接通过管道传输到 `bash` 是一种常见做法,但存在固有风险。对于生产服务器或独立服务器环境,建议先下载脚本,检查内容后再执行:
“`bash
curl -o install_nvm.sh https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh
cat install_nvm.sh # review before running
bash install_nvm.sh
“`
步骤 3:在当前 Shell 会话中激活 NVM
安装程序会修改您的配置文件,但这些更改仅在新的 shell 会话中生效。若要立即激活 NVM 而无需打开新终端:
对于 Bash:
“`bash
source ~/.bashrc
“`
对于 Zsh:
“`bash
source ~/.zshrc
“`
手动加载(适用于任何 shell):
“`bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
“`
常见问题:非交互式 Shell 中配置文件未被加载
在 Ubuntu 上,`~/.bashrc` 仅在交互式非登录 shell 中被加载。如果您通过 SSH 连接(登录 shell),Bash 会读取 `~/.bash_profile` 或 `~/.profile`。如果 SSH 登录后找不到 NVM,请将加载块添加到 `~/.bash_profile`:
“`bash
echo 'source ~/.bashrc' >> ~/.bash_profile
source ~/.bash_profile
“`
这是在远程服务器上配置 NVM 时最常遇到的问题之一。
步骤 4:验证 NVM 安装
“`bash
nvm –version
“`
预期输出(版本号可能有所不同):
“`
0.40.1
“`
如果命令返回 `nvm: command not found`,说明 shell 配置文件未正确加载。重新执行步骤 3 中的加载命令,并验证初始化块是否存在于您的配置文件中:
“`bash
grep -n 'NVM_DIR' ~/.bashrc
“`
步骤 5:使用 NVM 安装 Node.js
安装最新 LTS 版本(生产环境推荐)
“`bash
nvm install –lts
“`
`–lts` 标志用于安装最新的长期支持版本,该版本可获得 30 个月的安全补丁。对于在带 cPanel 的 VPS 或任何服务器环境上运行的生产工作负载,强烈建议使用 LTS 版本而非当前版本。
安装最新版本
“`bash
nvm install node
“`
安装特定版本
“`bash
nvm install 20.14.0
“`
列出所有可用的远程版本
“`bash
nvm ls-remote
“`
仅筛选 LTS 版本:
“`bash
nvm ls-remote –lts
“`
步骤 6:验证当前 Node.js 和 npm 版本
“`bash
node -v
npm -v
“`
同时确认二进制文件路径,以确保您没有意外使用系统级 Node.js 安装:
“`bash
which node
Expected: /home/<username>/.nvm/versions/node/v20.14.0/bin/node
“`
步骤 7:管理多个 Node.js 版本
列出所有本地已安装的版本
“`bash
nvm ls
“`
示例输出:
“`
-> v20.14.0
v18.20.3
v16.20.2
default -> lts/* (-> v20.14.0)
node -> stable (-> v20.14.0) (default)
lts/* -> lts/iron (-> v20.14.0)
“`
在版本之间切换
“`bash
nvm use 18.20.3
“`
此更改仅适用于当前终端会话。打开新终端将恢复为默认别名。
查看当前激活的版本
“`bash
nvm current
“`
步骤 8:设置持久默认 Node.js 版本
将特定版本设为所有新 shell 会话的默认版本:
“`bash
nvm alias default 20.14.0
“`
您也可以将别名设置为发布系列而非特定补丁版本,这样可以自动跟踪该系列内的更新:
“`bash
nvm alias default lts/*
“`
步骤 9:使用 `.nvmrc` 自动化版本切换
这是 NVM 最强大却最少被使用的功能之一。在项目根目录中放置一个包含所需 Node.js 版本的 `.nvmrc` 文件:
“`bash
echo "20.14.0" > /path/to/your/project/.nvmrc
“`
然后,当您 `cd` 进入该目录时:
“`bash
nvm use
Found '/path/to/your/project/.nvmrc' with version <20.14.0>
Now using node v20.14.0
“`
目录切换时自动切换版本
将以下内容添加到您的 `~/.bashrc`(或 `~/.zshrc`)中,以便在进入包含 `.nvmrc` 文件的目录时自动触发 `nvm use`:
对于 Bash:
“`bash
cdnvm() {
command cd "$@" || return $?
nvm_path="$(nvm_find_up .nvmrc | command tr -d 'n')"
if [[ ! $nvm_path = *[^[:space:]]* ]]; then
declare default_version
default_version="$(nvm version default)"
if [[ $default_version == "N/A" ]]; then
nvm use default
elif [[ $(nvm current) != "$default_version" ]]; then
nvm use default
fi
elif [[ -r "$nvm_path/.nvmrc" && -r "$nvm_path" ]]; then
declare nvm_version
nvm_version=$(<"$nvm_path/.nvmrc")
declare locally_resolved_nvm_version
locally_resolved_nvm_version="$(nvm ls –no-colors "$nvm_version" | command tail -1 | command tr -d '->*' | command tr -d '[:space:]')"
if [[ "$locally_resolved_nvm_version" == "N/A" ]]; then
nvm install "$nvm_version"
elif [[ $(nvm current) != "$locally_resolved_nvm_version" ]]; then
nvm use "$nvm_version"
fi
fi
}
alias cd='cdnvm'
“`
这种模式在 CI/CD 流水线和团队环境中尤为有价值,特别是当多名开发者在具有不同运行时要求的项目上协作时。
步骤 10:跨版本管理全局 npm 包
NVM 安装的每个 Node.js 版本都有其独立的 `node_modules` 目录用于全局安装的包。这意味着在 `v18` 下全局安装的 `pm2`、`yarn` 或 `typescript` 等工具在 `v20` 下不可用。
为当前版本安装全局包
“`bash
npm install -g yarn
npm install -g pm2
npm install -g typescript
“`
安装新版本时迁移全局包
NVM 提供了一个内置标志,可将所有全局包从一个版本复制到新安装的版本:
“`bash
nvm install 20.14.0 –reinstall-packages-from=18.20.3
“`
在升级由 PM2 或类似工具管理持久进程的服务器上的 Node.js 版本时,这一点至关重要。
列出当前版本的全局已安装包
“`bash
npm list -g –depth=0
“`
步骤 11:卸载某个 Node.js 版本
卸载前,请先切换到其他版本:
“`bash
nvm use 20.14.0
nvm uninstall 16.20.2
“`
您无法卸载当前激活的版本,尝试这样做将返回错误。
进阶:在非交互式环境中使用 NVM(CI/CD、Cron、Systemd)
NVM 依赖于 shell 初始化文件,而这些文件在非交互式 shell 中不会被加载。这会导致在 cron 任务、systemd 单元文件以及某些 CI 环境中出现 `node: command not found` 错误。
解决方案 1:使用完整的二进制文件路径
“`bash
/home/username/.nvm/versions/node/v20.14.0/bin/node /path/to/app.js
“`
解决方案 2:在脚本中显式加载 NVM
“`bash
#!/bin/bash
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"
nvm use 20.14.0
node /path/to/app.js
“`
解决方案 3:创建符号链接以实现系统级访问(谨慎使用)
“`bash
sudo ln -s /home/username/.nvm/versions/node/v20.14.0/bin/node /usr/local/bin/node
“`
这种方法会牺牲按用户隔离,但有时对于以专用服务用户身份运行的 systemd 服务是必要的。
NVM 在共享主机、VPS 与独立服务器上的对比
| 环境 | NVM 适用性 | 备注 |
|---|
| — | — | — |
|---|
| 共享主机 | 不支持 | 无 shell 访问权限;使用平台提供的 Node.js |
|---|
| [VPS 主机](https://alexhost.com/zh/vps/) | 极佳 | 完整 shell 访问权限;按用户隔离完美运行 |
|---|
| [独立服务器](https://alexhost.com/zh/dedicated-servers/) | 极佳 | 适用于多项目环境和 CI 运行器 |
|---|
| Docker 容器 | 部分支持 | 建议改用官方 Node.js Docker 镜像 |
|---|
| 共享虚拟主机 | 不支持 | 大多数配置下无 SSH 访问权限 |
|---|
对于在其他服务旁边运行 Node.js 应用程序的团队,VPS 可为您提供 NVM 所需的 shell 级控制,同时无需承担管理物理硬件的开销。
实用要点清单
将其作为部署和配置参考:
- 安装前确认 shell 类型(`echo $SHELL`)—— Zsh 和 Bash 需要不同的配置文件
- 生产环境 Node.js 安装始终使用 `–lts`;将 `node`(最新版)保留用于实验性工作
- 将 `.nvmrc` 提交到版本控制,以便每位团队成员和 CI 运行器使用完全相同的运行时版本
- 升级 Node.js 版本时使用 `–reinstall-packages-from`,避免手动重新安装全局工具
- 在任何非交互式脚本中显式加载 NVM(cron、systemd、CI 流水线)—— 切勿假设 shell 配置文件已被加载
- 切换版本后使用 `npm list -g –depth=0` 审查每个版本的全局包,以便尽早发现缺失的依赖项
- 在 `.nvmrc` 中锁定精确版本(例如 `20.14.0`)而非使用别名(例如 `lts`),以在生产环境中实现最大可复现性
- 切换版本后检查 `which node`,确认您没有意外使用系统安装的二进制文件
常见问题解答
NVM 安装 Node.js 是否需要 sudo 或 root 权限?
不需要。NVM 将所有内容安装在当前用户主目录下的 `~/.nvm` 中。安装或切换 Node.js 版本无需 root 权限。这是其相对于系统级包管理器的主要优势之一。
安装后为何出现 `nvm: command not found`?
NVM 初始化块已添加到您的 shell 配置文件中,但当前会话尚未重新加载该配置文件。请运行 `source ~/.bashrc`(Bash)或 `source ~/.zshrc`(Zsh)。如果打开新终端后错误仍然存在,请使用 `grep NVM_DIR ~/.bashrc` 检查初始化块是否确实已写入正确的文件。
同一服务器上的多个用户能否各自通过 NVM 使用不同的 Node.js 版本?
可以。由于 NVM 安装在每个用户的主目录中(`~/.nvm`),每个用户都维护一套完全独立的 Node.js 版本和全局包。这是多租户服务器的正确架构。
使用 NVM 切换 Node.js 版本后,全局安装的 npm 包会怎样?
每个 Node.js 版本都有其独立的全局包目录。在一个版本下全局安装的包对其他版本不可见。使用 `nvm install <new-version> –reinstall-packages-from=<old-version>` 可自动迁移这些包。
NVM 是否适合在服务器上的生产环境中运行 Node.js 应用程序?
NVM 非常适合管理所使用的 Node.js 版本,但在生产环境中进行进程管理时,您应将其与 PM2 等进程管理器配合使用,或使用 systemd 单元文件。请确保这些非交互式环境显式加载 NVM 或引用完整的二进制文件路径,如上文 CI/CD 部分所述。
