FAQ-15:在 Ubuntu 上安装 Node.js
预计阅读时间:16 分钟
📖 目录
问题速查表
| 问题 | 解决章节 |
|---|---|
| 安装最新 LTS 版本(生产环境推荐) | 方式一:使用 NodeSource 官方仓库(推荐) |
| 需要在多个版本之间切换 | 方式二:使用 nvm 管理多版本(最灵活) |
| 想一条命令快速安装 | 方式三:使用 Snap(最简但功能受限) |
| E: Unable to locate package nodejs | 错误一:E: Unable to locate package nodejs |
| npm install 报 EACCES 权限错误 | 错误二:npm install 报 EACCES 权限错误 |
| nvm 安装后命令找不到 | 错误三:nvm 安装后命令找不到 |
| node-gyp 编译原生模块失败 | 错误四:node-gyp 编译原生模块失败 |
Node.js 是构建后端服务、前端工具链和命令行工具的核心运行环境。无论是运行 JavaScript 项目、搭建 API 服务器,还是使用 npm/yarn 管理前端依赖包,都离不开它。Ubuntu 系统仓库自带的 Node.js 版本往往较旧,无法满足现代项目需求。本文提供三种安装方式,按推荐顺序排列,并附带版本管理、常见错误排查和最佳实践。
安装方法
方式一:使用 NodeSource 官方仓库(推荐)
NodeSource 维护了 Node.js 的 APT 仓库,支持安装所有主要版本,是生产环境最可靠的选择。
# 安装 NodeSource 仓库(以 Node.js 20 LTS 为例)
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# 安装 Node.js(包含 npm)
sudo apt install -y nodejs
# 验证安装
node --version
npm --version
如果需要安装 Node.js 18 LTS 或 22 LTS,只需将 setup_20.x 替换为 setup_18.x 或 setup_22.x。NodeSource 会自动添加对应的 APT 源和 GPG 密钥。
方式二:使用 nvm 管理多版本(最灵活)
nvm(Node Version Manager)是一个 bash 脚本,可以安装和管理多个 Node.js 版本,非常适合需要在不同项目间切换版本的开发者。
# 安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# 重新加载 shell 配置
source ~/.bashrc
# 安装最新 LTS 版本
nvm install --lts
# 安装指定版本
nvm install 18
nvm install 20
nvm install 22
# 切换版本
nvm use 18
nvm use 20
# 设置默认版本
nvm alias default 20
# 查看已安装版本
nvm list
# 查看可远程安装的版本
nvm ls-remote --lts
# 卸载某个版本
nvm uninstall 18
方式三:使用 Snap(最简但功能受限)
Snap 是 Ubuntu 自带的包管理器,安装一条命令搞定,但存在一些限制:无法全局安装 npm 包到自定义路径,某些原生模块编译可能失败。
# 安装 Node.js 20
sudo snap install node --classic --channel=20
# 验证
node --version
npm --version
注意:Snap 版本的 Node.js 运行在沙箱环境中,对文件系统访问有限制。如果项目需要访问项目目录之外的文件,建议使用前两种方式。
版本管理
在实际开发中,你可能同时维护多个项目,而不同项目要求不同的 Node.js 版本。以下是几种版本管理策略:
# 使用 nvm 在项目目录切换版本
cd ~/project-a
nvm use 18
cd ~/project-b
nvm use 20
# 在项目根目录创建 .nvmrc 文件,指定项目版本
echo "20" > .nvmrc
# 以后在该项目目录下执行以下命令即可自动切换到指定版本
nvm use
使用 NodeSource 时,如果需要升级到新版本,重新运行安装脚本即可覆盖安装,不会产生冲突。而使用 Snap 时,可以通过 --channel 参数指定版本频道。
# nvm 常用命令速查
nvm ls-remote --lts # 查看远端可用 LTS 版本列表
nvm install 20 # 安装指定版本
nvm use 20 # 当前 shell 切换版本
nvm alias default 20 # 设置默认版本(新终端生效)
nvm current # 查看当前版本
nvm ls # 列出本机已装版本
nvm uninstall 20 # 卸载指定版本
# 卸载 NodeSource 安装的 Node.js
sudo apt remove -y nodejs
sudo rm -f /etc/apt/sources.list.d/nodesource.list
sudo apt update
nvm 与 NodeSource 混用注意事项:两者会同时修改 PATH 顺序,谁先 export 谁生效。如果安装了 nvm 后 `node` 仍指向 /usr/bin/node,说明 nvm 的初始化脚本未优先执行——把 nvm 的 export 语句放在 ~/.bashrc 靠前的位置,或在当前 shell 执行 nvm use --delete-prefix 20 修复。
真实案例
案例 A:cron 任务报 node: command not found,但手动执行正常
用户通过 NodeSource 安装 Node.js 后,在 crontab 中定时运行一个 Node 脚本,邮件报错 node: command not found,但手动在终端执行同一命令却完全正常。
# cron 邮件中的报错
/bin/sh: 1: node: not found
# 排查:cron 的最小 PATH 不含 /usr/bin 之外的自定义路径
# 手动环境
which node # /usr/bin/node(NodeSource 安装时会链接到 /usr/bin)
# cron 环境 PATH 只有 /usr/bin:/bin,如果 node 不在其中就会失败
crontab -e
# 修复:在 crontab 顶部显式声明 PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/5 * * * * node /home/user/scripts/check.js
根因:cron 运行时的最小环境 PATH 与登录 shell 不同;修复:在 crontab 中显式声明 PATH;验证:手动执行 crontab -l 后等待下一周期,观察任务输出正常。
案例 B:npm install -g 报 EACCES 权限错误
# 报错
npm ERR! code EACCES
npm ERR! syscall mkdir
npm ERR! path /usr/lib/node_modules/cowsay
npm ERR! Error: EACCES: permission denied, mkdir '/usr/lib/node_modules/cowsay'
# 排查:npm 默认全局目录是 /usr/lib/node_modules,需要 root 权限
npm config get prefix # /usr/local(或 /usr/lib)
# 修复:将全局目录改到用户目录(参考"错误二"方案)
mkdir -p ~/.npm-global
npm config set prefix ~/.npm-global
echo 'export PATH=$PATH:~/.npm-global/bin' >> ~/.bashrc
source ~/.bashrc
npm install -g cowsay # 成功,无需 sudo
根因:全局 npm 包目录无写权限;修复:改 prefix 到用户目录(比 sudo npm 更安全,避免第三方包以 root 运行);验证:cowsay hello 直接可用,npm root -g 指向 ~/.npm-global/lib/node_modules。
案例 C:nvm install 卡在 downloading 进度条
用户通过 nvm 安装 Node.js 20 时,进度条停在 50% 不动,最终超时报错 nvm install 20: download timed out。
# 报错
$ nvm install 20
Downloading and installing node 20.x.x...
# 进度条卡住,等待超时报错
# nvm install 20: download timed out after 300s
# 排查:nvm 默认从 nodejs.org 下载,国内可能被墙
# 检查网络
curl -I https://nodejs.org/dist/v20.11.0/
# 超时或极慢
# 修复:设置 NVM_NODEJS_ORG_MIRROR 使用国内镜像
echo 'export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node' >> ~/.bashrc
source ~/.bashrc
# 重试安装
nvm install 20
# 秒级完成
根因:nodejs.org 在国内网络环境下访问不稳定;修复:设置 NVM_NODEJS_ORG_MIRROR 环境变量指向国内镜像;验证:nvm install 20 正常完成,node --version 输出 v20.x.x。
案例 D:npm ci 报 integrity check failed
CI 环境执行 npm ci 报错 npm ERR! code EINTEGRITY,但本地正常。
# 报错
npm ERR! code EINTEGRITY
npm ERR! sha512-xxxx mismatch for registry.npmjs.org/lodash/-/lodash-4.17.21.tgz
# 排查:package-lock.json 与 npm registry 的 sha512 不一致
# 可能原因:本地 node_modules 缓存污染,或 package-lock 被手动修改
# 修复:删除锁文件和缓存,重新生成
rm -rf node_modules package-lock.json
npm cache clean --force
npm install # 重新生成 package-lock.json
# 验证
npm ci # 成功
根因:package-lock.json 中的完整性校验值与 registry 不匹配(常因缓存污染或锁文件损坏);修复:清除缓存重新生成锁文件;预防:CI 中不要手动修改 lock 文件,提交 package-lock.json 到 Git。
案例 E:npm update 报 ERR! code ERESOLVE unable to resolve dependency tree
执行 npm update 或 npm install 时遇到依赖冲突无法解决。
# 报错
npm ERR! code ERESOLVE
npm ERR! ERESOLVE could not resolve
npm ERR! While resolving: myapp@1.0.0
npm ERR! Found: react@18.2.0
npm ERR! node_modules/react
npm ERR! react@"^18.2.0" from the root project
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^17.0.0" from some-legacy-pkg@2.1.0
# 排查:some-legacy-pkg 要求 react 17,但项目用 react 18
# 方法一:强制安装(跳过 peer 依赖检查)
npm install --legacy-peer-deps
# 方法二:查找兼容版本
npm info some-legacy-pkg versions # 看有没有支持 react 18 的新版本
npm install some-legacy-pkg@latest # 升级到最新版
根因:npm 7+ 默认严格检查 peer 依赖冲突,旧包的 peer 依赖声明未更新;修复:优先升级依赖到兼容版本,--legacy-peer-deps 作为临时方案;预防:CI 中固定 --legacy-peer-deps 或及时更新上游依赖。
版本管理详解
nvm 完整使用指南
nvm 是 Node.js 版本管理的事实标准,以下是进阶用法:
# 安装特定架构版本(适用于 ARM 服务器)
nvm install 20 --arch=arm64
# 安装并立即使用
nvm install 20 --default # 安装并设为默认
# 从远程安装指定子版本
nvm install 20.11.0
# 查看本机已安装版本(带当前激活标记)
nvm ls
# v18.19.0
# -> v20.11.0
# v22.12.0
# 列出远程可用 LTS 版本(含 codename)
nvm ls-remote --lts | grep "v20\."
# v20.11.0 2024-01-09
# v20.11.1 2024-02-14
# v20.12.0 2024-04-09
# 在当前 shell 切换版本(不新建 shell)
nvm use 20
# 切换版本时自动安装(如果本地没有)
nvm use 22 # 如果 22 未安装,报错
nvm install 22 && nvm use 22 # 先装再切换
# 为某个版本创建别名
nvm alias lts/iron 20.11.0 # 铁 = Node 20 LTS 的 codename
nvm use lts/iron
# 卸载版本前确认没有进程在用
lsof +D $(nvm which 18) 2>/dev/null && echo "有进程在用,先 kill" || nvm uninstall 18
# .nvmrc 支持更多语法
echo "20" > .nvmrc # 最新 20.x
echo "lts/iron" > .nvmrc # 指定 LTS codename
echo "20.11.0" > .nvmrc # 精确版本
# 自动加载 nvm(在 shell 初始化脚本中)
# ~/.bashrc 或 ~/.zshrc 末尾
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
n vs nvm 对比
另一个流行的版本管理工具是 n,它是一个 Node.js 脚本(不像 nvm 是 bash 脚本),安装更简单:
# 安装 n
npm install -g n
# 使用 n 安装版本
n 20 # 安装最新 20.x
n lts # 安装最新 LTS
n latest # 安装最新版
n 18.19.0 # 精确版本
# 查看已安装版本
n ls
# 切换版本(修改 /usr/local/bin/node 符号链接)
n # 交互式选择
# 注意:n 安装到系统目录,需要 sudo
sudo n 20
# nvm 与 n 的区别
# nvm: 用户级,不需 sudo,隔离性好,适合多项目多版本
# n: 系统级,需 sudo,更简单,适合单版本快速切换
项目级版本锁定最佳实践
# 方案一:.nvmrc 文件(团队协作标准)
echo "20.11.0" > .nvmrc
# 团队成员进入项目目录后执行 nvm use 自动切换
# 方案二:package.json engines 字段
cat package.json | jq '.engines'
# {
# "node": ">=20.0.0 <23.0.0",
# "npm": ">=10.0.0"
# }
# npm install 时会检查 Node 版本,不满足则报错
# 方案三:volta(更现代的方案)
curl https://get.volta.sh | bash
volta pin node@20.11.0 # 写入 package.json
volta pin npm@10.5.0
# 方案四:GitHub Actions 中使用
cat > .github/workflows/ci.yml << 'EOF'
steps:
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
EOF
故障排查决策树
当 Node.js 环境出现问题时,按以下流程逐步排查:
问题:node 或 npm 命令找不到
├── which node 有输出?
│ ├── 是 → PATH 没问题,检查别名:alias | grep node
│ └── 否 → 查找安装位置:
│ ├── ls /usr/bin/node* /usr/local/bin/node* 2>/dev/null
│ │ ├── 有 → 加入 PATH:export PATH=$PATH:/usr/local/bin
│ │ └── 无 → Node.js 未安装,选择安装方式
│ └── nvm 环境?
│ ├── nvm ls 查看已安装版本
│ ├── nvm use 激活
│ └── source ~/.bashrc 重新加载 nvm 初始化
问题:npm install 报错
├── EACCES 权限错误?
│ ├── 是 → 修改 prefix:mkdir ~/.npm-global && npm config set prefix ~/.npm-global
│ └── 否 → 继续排查
├── ERESOLVE 依赖冲突?
│ ├── 是 → npm install --legacy-peer-deps 或升级冲突依赖
│ └── 否 → 继续排查
├── EINTEGRITY 校验失败?
│ ├── 是 → rm -rf node_modules package-lock.json && npm cache clean --force && npm install
│ └── 否 → 继续排查
├── ENOENT 文件不存在?
│ ├── 是 → 检查 package.json 是否存在,依赖名是否正确
│ └── 否 → 检查网络:curl -I https://registry.npmjs.org/
问题:node-gyp 编译失败
├── 安装 build-essential:sudo apt install -y build-essential python3
├── 检查 Node 版本兼容性:某些原生模块不支持最新 Node
├── 使用 --build-from-source 重试:npm install sharp --build-from-source
└── 考虑使用预编译版本:npm install @img/sharp-linux-x64
问题:Node 版本不兼容
├── 报错:This version of Node.js is not supported
│ ├── 查看项目要求:cat package.json | grep engines
│ ├── 切换版本:nvm install && nvm use
│ └── 升级 Node:nvm install --lts && nvm use --lts
问题:npm 全局包路径问题
├── npm root -g 检查全局目录
├── npm config get prefix 检查前缀
├── 确认 PATH 包含 $(npm prefix -g)/bin
└── 修复:echo 'export PATH="$PATH:$(npm prefix -g)/bin"' >> ~/.bashrc
生产环境配置建议
- 使用 LTS 版本 + NodeSource 仓库:生产环境推荐 Node.js 20 LTS(或 18 LTS),通过 NodeSource 安装,配合
apt-mark hold锁定版本防止意外升级。 - 进程管理使用 PM2 或 systemd:不要直接
node app.js启动服务。PM2 提供集群模式、日志管理、自动重启;systemd 提供原生系统级管理。 - 设置NODE_ENV=production:在生产环境中显式声明环境变量,许多库会据此优化性能(如 Express 关闭详细错误栈、React 关闭开发检查)。
- 限制内存使用:Node.js 默认堆内存上限约 1.5GB(64位系统),大数据量场景需要调整:
node --max-old-space-size=4096 app.js。 - 监控日志和指标:生产环境应配置日志轮转(logrotate)、应用指标监控(Prometheus + Grafana),及时发现内存泄漏、事件循环延迟等问题。
- 安全扫描依赖:定期运行
npm audit检查已知漏洞,配合npm audit fix自动修复,CI 中加入 audit 步骤作为安全卡点。 - Docker 部署建议:多阶段构建减小镜像体积(builder 阶段安装依赖,runtime 阶段只复制 node_modules 和应用代码),使用 alpine 基础镜像。
案例 F:npm run script 报错找不到命令
项目 package.json 中定义了 "dev": "vite",执行 npm run dev 报 vite: command not found。
# 报错
npm ERR! Missing script: "dev"
# 或
sh: 1: vite: not found
# 排查:vite 是否安装在 node_modules/.bin
ls node_modules/.bin/vite
# 文件不存在
# 原因:node_modules 未安装或不完整
# 解决:重新安装依赖
rm -rf node_modules package-lock.json
npm install
# 验证
ls node_modules/.bin/vite # 存在
npm run dev # 正常启动
# 如果是 monorepo 项目
# 确认在正确的 package 目录下执行
cd packages/web && npm install && npm run dev
根因:node_modules 未安装或安装不完整,导致 node_modules/.bin 中缺少可执行文件;修复:清理后重新 npm install。
案例 G:Node.js 版本与 npm 版本不兼容
升级 Node.js 后 npm 报错 npm WARN npm does not support Node.js,npm 版本过旧。
# 报错
npm WARN npm does not support Node.js v22.0.0
npm WARN You should probably upgrade to a newer version of node as we
npm WARN can no longer makeguarantees that npm will work with this version
# 排查
node --version # v22.0.0
npm --version # 9.6.7(配套 Node 20 的 npm,不兼容 22)
# 原因:Node.js 22 自带的 npm 需要重新安装或更新
# 修复:升级 npm
npm install -g npm@latest
# 或使用 Node.js 自带的 corepack
corepack enable
corepack prepare npm@latest --activate
# 验证
npm --version # 10.x.x(兼容 Node 22)
根因:Node.js 版本升级后 npm 未同步更新,版本不兼容;修复:执行 npm install -g npm@latest 升级 npm;预防:使用 nvm 管理版本时,每次安装新 Node 版本后验证 npm 版本。
案例 H:nvm 切换版本后全局包丢失
用户切换 Node 版本后,之前全局安装的工具(如 typescript)报 command not found。
# 现象
nvm use 20
tsc --version # /usr/bin/env: 'node': No such file or directory
# 或
tsc: command not found
# 原因:nvm 每个版本的全局包是隔离的
# Node 18 下全局安装的 tsc 在 Node 20 下不可用
# 修复:在新版本下重新安装
nvm use 20
npm install -g typescript
# 批量迁移全局包
nvm use 18
npm list -g --depth=0 # 查看全局包列表
nvm use 20
npm install -g $(npm list -g --depth=0 --parseable | tail -n +2 | xargs -I{} basename {})
# 或使用 nvm 的 alias 功能
nvm alias default 20
nvm use default
根因:nvm 每个版本的全局包独立存储,切换版本后原全局包不可用;修复:在新版本下重新安装全局包,或使用脚本批量迁移。
卸载与切换
# 卸载 NodeSource 的 Node.js(保留配置文件可用 --purge)
sudo apt purge -y nodejs
rm -f /etc/apt/sources.list.d/nodesource.list
# 卸载 Snap 版本
sudo snap remove node
# nvm 卸载指定版本
nvm uninstall 18
# 完全移除 nvm(删除目录和配置行)
rm -rf ~/.nvm
# 并手动删除 ~/.bashrc 中的 nvm 初始化行
常见错误
错误一:E: Unable to locate package nodejs
这通常是因为 NodeSource 仓库没有正确添加。请确认:
# 检查仓库是否已添加
ls /etc/apt/sources.list.d/nodesource.list
# 如果不存在,重新执行安装脚本
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
# 更新包索引后重试
sudo apt update
sudo apt install -y nodejs
错误二:npm install 报 EACCES 权限错误
不要用 sudo 运行 npm install。正确做法是修改 npm 的全局安装路径:
# 创建全局目录
mkdir -p ~/.npm-global
# 配置 npm 使用该目录
npm config set prefix ~/.npm-global
# 将路径加入 PATH
echo 'export PATH=$PATH:~/.npm-global/bin' >> ~/.bashrc
source ~/.bashrc
# 之后就可以不带 sudo 安装全局包了
npm install -g typescript
错误三:nvm 安装后命令找不到
nvm 修改的是 shell 的环境变量,安装后需要重新加载配置文件:
source ~/.bashrc
# 或者重新打开终端窗口
# 确认 nvm 已加载
nvm --version
错误四:node-gyp 编译原生模块失败
某些 npm 包(如 sharp、bcrypt)需要编译原生 C++ 代码,缺少构建工具会报错:
# 安装编译工具链和 Python
sudo apt install -y build-essential python3
# 之后重新安装有问题的包
npm install sharp
验证安装
# 检查版本
node --version
npm --version
# 运行一个简单的 HTTP 服务器测试
node -e "require('http').createServer((req, res) => { res.end('Hello from Node.js ' + process.version); }).listen(3000)" &
# 等待服务器启动后测试
sleep 1
curl http://localhost:3000
# 停止测试服务器
kill %1
# 测试 npm 全局安装功能
npm install -g cowsay
cowsay "Node.js is working!"
最佳实践
- 优先选择 LTS 版本:生产环境应使用 LTS(长期支持)版本,如 18.x 或 20.x,它们有更长的安全更新周期。
- 不要用 sudo 运行 npm:全局安装的包应该放在用户目录下,避免权限污染和安全风险。
- 使用 .nvmrc 锁定版本:团队协作时在项目根目录放置
.nvmrc文件,确保所有开发者使用相同版本。 - 定期更新 npm:npm 本身会频繁发布安全更新,运行
npm install -g npm@latest保持最新。 - 考虑使用 corepack:Node.js 16+ 内置 corepack,可以管理 yarn/pnpm 的版本,运行
corepack enable即可激活。 - 固定版本并提交锁文件:项目提交
package-lock.json,CI 与生产用npm ci(而非 npm install)保证依赖一致。 - CI 中指定 Node 版本:GitHub Actions 用
actions/setup-node的node-version-file: .nvmrc自动读取项目版本,避免"本地能跑 CI 挂了"。 - 非交互环境验证:安装后执行
command -v node确认 PATH 生效,避免脚本(cron/systemd)中找不到命令。
延伸阅读
- 1.8:软件包管理 软件包管理——APT、Snap、PPA 管理
- 3.3:实战:搭建个人网站 搭建个人网站——部署 Node.js 应用到服务器
案例 I:npm cache 损坏导致安装失败
现象:执行 npm install 时反复报 EINTEGRITY 或 ECONNRESET 错误,清除 node_modules 后仍然失败:
# 报错
npm ERR! code EINTEGRITY
npm ERR! sha512-xxxx mismatch for registry.npmjs.org/lodash/-/lodash-4.17.21.tgz
# 清除缓存后重试
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
# 仍然报同样的错误
排查过程:
# 检查 npm 缓存目录
$ ls ~/.npm/_cacache/
index-v5/ content-v2/
# 完整清除缓存
$ rm -rf ~/.npm/_cacache
$ npm cache clean --force
# 验证 registry 连接
$ npm config get registry
https://registry.npmjs.org/
$ curl -I https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz
HTTP/2 200
根因:npm 缓存中的完整性校验文件损坏,导致每次安装都验证失败。即使清除 node_modules,缓存中的损坏数据仍然被使用。
修复:
# 完整清除 npm 缓存
rm -rf ~/.npm/_cacache
npm cache clean --force
# 重新安装
npm install
# 验证
npm install lodash # 成功
预防:CI 环境中定期执行 npm cache clean --force。遇到完整性错误时优先清除缓存而非反复重试。