资讯详情

资讯详情

Linux 下用 nvm 升级 Node.js 到指定版本:安装、切换与回滚全指南

前阵子帮人处理一台 Linux 服务器对方想跑一个依赖 Node.js 新特性的工具结果node -v打出来还是 18.x。按老思路要么用系统包管理器升级要么去官网下二进制包直接替换可那是台带着线上服务的机器谁也不敢乱动/usr/bin和/usr/local底下的东西。我当时的建议就是四个字母nvm。如果你也想在 Linux 上把 Node.js / npm 精确升级到 Node v23.x、npm 10.x 这种“指定版本”同时又不想污染系统目录、不想 root 权限满天飞、不想回滚时两眼一抹黑那用 nvm 是当前最省心的一条路。这篇文章不打算讲虚的会把安装、切换、升级、回滚、踩坑整个链路都过一遍。1. 为什么我坚持用 nvm 做升级而不是动系统的包很多人在 Linux 上升级 Node.js 的第一反应是走发行版包管理器比如 Debian/Ubuntu 系里的apt upgrade nodejs。这套方案的痛点是版本不可控软件源里的 Node.js 版本基本由发行版发布时冻结很多 LTS 系发行版仓库里的版本相当保守你想装 Node v23.x 这种较新的版本源里根本没有。强行加第三方源、换仓库、手动打包又是一连串新坑。直接下载官方二进制包替换/usr/local/bin/node也常见但这属于“手工爆破式升级”。你需要 root 权限覆盖系统目录全局 npm 包的路径、权限、软链关系全靠手动维护最麻烦的是回滚——升级前如果不提前备份几乎没法干净地退回旧版。我在这里直接把几种常见方案放在一起对比看完你就明白为什么 nvm 更合适方案版本可控性系统侵入性回滚难度适用场景系统包管理器安装低绑定仓库版本高会改动系统包中等可能牵连系统依赖对版本无要求、纯系统集成官方二进制包手动解压中可指定版本高覆盖系统目录高需手动备份恢复临时环境、一次性部署源码编译中可指定版本中高依赖残留多特殊架构、定制编译参数nvm 版本管理高可按大版本或精确版本安装极低只写用户家目录极低一条命令切换版本本地开发、服务器多项目并存、升级测试nvm 的核心思路很朴素把每个版本的 Node.js 完整地装进用户目录下的独立目录然后通过修改 shell 的PATH环境变量来决定“当前用哪个版本”。它从头到尾不碰系统目录不碰/usr/bin/node不依赖 apt/dpkg 的数据库。系统里的包随便升级nvm 这边互不干扰。这也是“不破坏系统”这句话的真正含义。你升级 Node.js本质上只是在用户目录里多放了一个新版本目录再把默认切换指针指向它而已。1.1 直接替换系统路径的隐患我见过不止一次有人图省事直接sudo cp -r node-v23.x-linux-x64/* /usr/local/看起来 node 命令确实变成了新版但坑马上来了第一/usr/bin/node或/usr/local/bin/node被替换后所有依赖旧版行为、旧版 ABI 的工具都可能出问题。尤其是一些通过node-gyp编译过的原生模块经常和新版 Node 的 ABI 不兼容报错信息五花八门。第二全局 npm 包目录的权限变成 root 所有之后想装一个全局包就得一直加sudo。而sudo环境下的PATH和普通用户不一样经常会遇到“下了 sudo 反而找不到 node”的怪问题。第三回滚很难。你重新把旧文件拷回去万一忘了备份某个软链或者漏了一个/usr/lib/node_modules下的目录系统状态就对不上了。nvm 不存在这些问题因为它每个版本目录都是独立、完整、可随时删除的。2. 动手前先摸清家底版本、全局包、系统依赖升级这种事最忌讳一上来就curl | bash。我先花两分钟把当前环境摸清楚这能帮你少踩一半坑。2.1 升级前必须做的四件事在安装 nvm 之前我通常会依次执行下面这些命令并且把输出抄下来留着后面对比node -v npm -v which node which npm然后导出当前 Node.js 环境里已安装的全局包清单npm ls -g --depth0这步很重要。系统里已有的全局 CLI 工具比如某些脚手架、构建工具、命令行工具在切换版本后不会自动带过来后面你得知道它们原本存在过。我习惯顺手把这份清单存到一个临时文件里当作迁移基准。接下来检查系统包里到底有哪些东西依赖 nodejsapt-cache rdepends nodejs这一条在 Debian/Ubuntu 系下可以看到“哪些包依赖 nodejs”。比如某些桌面环境组件、某些开发工具链、某些编辑器插件都可能把 nodejs 当成系统依赖。知道这件事之后你就不会产生“反正装了 nvm干脆把系统 node 卸载”这种危险冲动。最后看一眼家目录里是不是已经存在 nvm 的痕迹ls -d ~/.nvm 2/dev/null nvm --version 2/dev/null || echo no nvm found有些机器可能以前装过 nvm 但后来没用了先确认清楚避免重复安装把 shell 配置搞乱。2.2 “指定版本”到底指哪种指定标题里的“Node v23.x、npm 10.x”其实是两种不同粒度的指定。理解这一点后面的命令才不会打错。Node 23 是奇数版本不是 LTS长期支持版本所以它更适合希望提前体验新特性、做预研验证的场景。如果你是在生产环境我建议还是优先选 LTS 版本但如果你明确需要 Node 23 的某些能力那么用 nvm 临时跑它完全没问题反正随时可以切回其他版本。nvm 对版本号的处理很灵活nvm install 23自动解析成当前最新的 23.x 小版本适合“我就要 23 这个大版本”的场景。nvm install 23.x.x精确安装某个具体小版本适合团队统一版本、复现问题的场景。nvm install node装最新版 Node一般用于尝鲜。如果你想看远程到底有哪些版本可选在安装前先执行nvm ls-remote 23会列出所有匹配 23.x 的远程版本号。这样你就知道接下来nvm install 23实际会装哪一个版本。3. nvm 安装与初始化从脚本到终端生效nvm 的安装方式不算复杂但有几个细节会影响后续体验。3.1 官方脚本安装与原理说明官方推荐的安装方式是一行脚本。以 bash 为例curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.x/install.sh | bash注意上面地址里的v0.40.x是示例版本号nvm 自己的版本会迭代。我建议你直接到 nvm 官方仓库的 README 页面复制最新的安装命令那才是最稳的。千万不要凭记忆敲一个旧版本号装完才发现 nvm 本身太老对新版 Node 的解析支持不完整。这个脚本实际做的事可以拆成几步把 nvm 的仓库代码 clone 到~/.nvm目录然后在当前用户 shell 配置文件~/.bashrc、~/.zshrc等里追加几行加载逻辑。之后每次打开终端shell 都会加载 nvm 的函数定义。如果你不希望直接执行从网络下载的脚本也可以用官方文档里的 git 方式安装git clone https://github.com/nvm-sh/nvm.git ~/.nvm cd ~/.nvm ./install.sh两种方式本质一样。我还遇到过一些特殊环境服务器根本无法直接访问外网这时候可以在一台能访问网络的机器上把 nvm 仓库完整打包传到目标机手动解压到~/.nvm再执行install.sh。离线安装完全可行只是手动步骤多一些。3.2 当前终端立即生效安装脚本结束后终端里大概率还找不到nvm命令因为当前 shell 会话还没有重新加载配置文件。这时最省事的方法是把终端关掉重新打开但很多人不习惯其实手动 source 一下就行source ~/.bashrc如果你是 zsh对应执行source ~/.zshrc。然后验证nvm --version这里有个容易误判的细节nvm是一个 shell 函数不是一个位于/usr/bin下的可执行文件。你执行which nvm有时可能没有输出或者输出的是 shell 函数的定义信息这不代表 nvm 没装好。判断标准应该是nvm --version能正常打印版本号。3.3 网络环境不好时的下载处理nvm 安装 Node.js 时默认从 Node.js 官方发布地址下载二进制包。如果服务器网络环境不佳下载容易超时或者进度条卡半天。nvm 支持通过环境变量NVM_NODEJS_ORG_MIRROR指定下载镜像。我通常会在 shell 配置文件里加一行环境变量指向可用的 Node.js 发行镜像源。示例写法如下export NVM_NODEJS_ORG_MIRRORhttps://你的镜像站点/nodejs-dist加了这行之后nvm install会自动从镜像下载。这里一定要分清NVM_NODEJS_ORG_MIRROR只影响 nvm 下载 Node.js 二进制文件它不影响 npm 安装第三方包时使用的 registry。想把 npm 的包源切到镜像那是单独配置~/.npmrc里registry字段的事。我见过有人把这两个概念混在一起折腾半天发现 nvm 还是慢其实是变量配错了对象。4. 安装 Node v23.x 并切到默认版本环境准备就绪之后真正的重头戏来了把当前 Node.js 升级到 Node v23.x。4.1 先查远程版本再执行 install我不太建议闭着眼睛直接nvm install 23虽然这样也会有结果。更稳妥的顺序是先用远程列表确认一下目标nvm ls-remote 23这条命令会列出所有可用的 23.x 远程版本你能看到这个系列目前已经推进到哪个小版本了。确认之后执行nvm install 23nvm 会把 23 解析成当前最新的 23.x 版本并开始下载。下载完成后它会自动解压到~/.nvm/versions/node/目录下生成类似v23.x.x的独立目录。整个过程不需要 root 权限因为写入位置完全在用户目录中。装完后 nvm 通常会提示你“当前已切换到新版”不过我还是建议手动再执行一次nvm use 23然后检查效果node -v这时候你大概率会看到v23.x.x。但只要新开一个终端窗口版本可能又变回去了。这是 nvm 新手最容易懵的点原因在下一节。4.2 设置默认 alias避免版本回跳nvm 有一个“默认版本”的概念每次新开终端时nvm 会根据默认 alias 自动决定启用哪个 Node 版本。如果你只执行了nvm use 23它只对当前 shell 会话生效会话一关就没了。要让 Node 23 成为这个用户默认使用的版本执行nvm alias default 23这个命令的本质是在~/.nvm/alias/default文件里写入字符串23。以后每次打开终端nvm 看到 default 是 23就会自动使用 23.x 的最新已安装版本。如果你希望某个特定小版本成为默认也可以把23换成具体的23.x.x。我个人习惯用大版本号当 default这样以后nvm install 23更新到新的小版本后下次开终端自动就是新小版本了比较省事。4.3 验证路径确认系统 node 仍然健在“不破坏系统”不是嘴上说说最好用实际路径验证一下which node command -v node echo $PATH此时which node的输出应该指向~/.nvm/versions/node/v23.x.x/bin/node而不是/usr/bin/node。这说明 PATH 环境变量里nvm 版本的目录优先级排在了系统目录前面。同时你再执行ls -l /usr/bin/node系统目录里的旧 Node 依然存在。它并没有被删除只是暂时“竞争”不过 nvm 目录。这就是不破坏系统的核心体现新旧版本共存切换靠 PATH 优先级而不是靠覆盖文件。5. 把 npm 精确升级到 10.xNode.js 升级完成后很多人会忽略 npm 的版本。Node v23.x 自带的 npm 版本大概率已经是 10.x 系列但如果你想精确锁定到 npm 10.x 的最新版或者希望从更早的 npm 版本一步到位升到 10.x仍然需要单独的几步操作。5.1 npm 版本跟着谁走首先要理解 npm 的版本管理在 nvm 环境下的特殊之处。npm 是随 Node.js 一起分发的理论上每个 nvm 版本目录里的 npm 都是独立的一份。当你执行nvm use 23之后npm -v显示的是v23.x.x这个 Node 版本出厂时自带的 npm 版本。如果你之前用旧版 Node 时手动升级过全局 npm那个升级结果只存在于旧版本目录里。切换版本后新版目录里仍然是出厂 npm。这正是很多人升级完 Node 之后发现 npm 版本不对的原因不是没升级而是“升级到了别的版本的背包里”。另外nvm 提供了一个便捷命令nvm install-latest-npm它会把当前激活的 Node 版本的 npm 升级到与之兼容的最新版本。但如果你想精确控制到 10.x我不建议用这条命令因为你无法指定大版本号。5.2 用 npm10 标签锁定版本在 nvm 管理下升级全局 npm 的操作和平时几乎一样nvm use 23 npm install -g npm10这里的关键是npm10这个写法。npm 官方仓库使用 dist-tag 来标记发布流npm10表示“10.x 系列的最新发布版”。执行完之后新版 npm 会被安装到当前 Node 版本的全局目录你可以验证npm -v安装来源本身是 npm 的 registry所以如果之前配置过 registry 镜像这一步会走镜像速度一般没问题。问题在于这一步和前面nvm ls-remote下载 Node 二进制是两套通道别混为一谈。如果你想精确到某个小版本也可以把10换成完整的版本号比如npm10.9.2这种格式的写法。不过日常使用中npm10已经足够精确了它既保证不跳到 11 或 12 大版本又能拿到 10.x 里最新的修复。5.3 全局包在新版本下怎么办npm 升级完之后你可能会发现之前的全局包在新 Node 版本里都没了。这是 nvm 的正常行为不是说包丢了而是不同版本目录下的全局包互相独立。升级前可以先用npm ls -g --depth0看一下当前版本的全局包。如果是从旧版本切换过来nvm 提供了一个迁移辅助命令nvm reinstall-packages这条命令会读取默认 alias 对应版本里的全局包清单然后把它们重新安装到当前激活的版本里。但它不是万能的对于那些依赖原生模块编译的工具重装后大概率还需要在新版本环境下重新编译命令可能还会报错。更稳妥的迁移方式是手动保留清单切换到目标版本后按需重新安装。我的建议是全局包能少装就少装。真正属于项目的依赖应该写在各自项目的package.json里全局只保留真正高频使用的 CLI 工具。这样切版本时的迁移成本会低很多。6. 升级后的善后回滚、锁定、系统包取舍升级完成不等于收工还有几件善后工作值得做。尤其是你面对一台长期运行的 Linux 服务器时回滚方案和项目版本锁定同样重要。6.1 回滚到旧版本其实很简单nvm 最大的心理安慰是升级错了也几乎零成本。你想回到升级前的 Node 版本只需要知道旧版本号。如果你还记得旧版本直接nvm use 18.20.4 nvm alias default 18.20.4如果你不记得旧版本可以执行nvm ls查看本地已经安装的所有版本然后选择。如果你想彻底回到“系统原始 node”可以执行nvm use system这个命令会把 PATH 切回系统自带 Node。因为整个升级过程中系统目录从未被动过所以这个回滚动作永远可用。6.2 用 .nvmrc 固定项目版本在团队协作场景里仅仅“个人默认版本”锁定还不够。同一个项目你这边跑 Node 23同事那边跑 Node 18行为可能完全不同。nvm 支持项目级版本锁定文件.nvmrc。在项目根目录创建这个文件内容写上大版本号或完整版本号echo 23 .nvmrc之后进入目录执行nvm usenvm 会读取.nvmrc并自动切换到对应版本。这比口头约定版本号靠谱得多。需要说明的是nvm 默认不会在你每次进入目录时自动读取.nvmrc得手动nvm use或者借助编辑器插件、shell 钩子实现自动切换。不要指望它默认就有自动魔法。6.3 系统里原有 Node 包别急着删用 nvm 升级完 Node 之后系统里那个旧版/usr/bin/node其实没有必要立刻删除。原因有两个一是很多系统级工具在安装时就把nodejs当成了依赖。贸然执行apt remove nodejs可能触发一连串依赖变化轻则删除某些组件重则影响桌面环境或者系统服务。二是留着旧版没有任何坏处。nvm 通过 PATH 优先级让新版生效旧版只是暂时“隐身”。一旦某些第三方脚本明确使用/usr/bin/node绝对路径调用旧版它依然能工作。这在排查“某个服务为什么用的是旧版本”时反而是一张安全网。如果你实在想清理先看依赖关系再决定。Debian/Ubuntu 系统上可以执行apt-cache rdepends nodejs如果输出结果为空或者只有你自己装过的包依赖它那才考虑卸载。否则我建议保留不动它。7. 我实际踩过的坑与排查思路最后分享几条我踩过、也帮别人排查过的实际问题。每一条都是真实场景里容易卡住人的点。7.1 新开终端 node 又变回旧版现象终端的node -v明明是 23.x但只要关掉终端重新开一个窗口版本就变回老的 18.x。根因默认 alias 没有设置。执行nvm use 23只对当前会话生效新会话启动时 nvm 读取 default alias。如果 default 指向的还是一个旧版本自然就切过去了。排查思路nvm alias default cat ~/.nvm/alias/default 2/dev/null执行结果会告诉你当前默认版本指向哪。修复方式nvm alias default 237.2 sudo 环境下找不到 node现象普通用户终端里node -v正常执行sudo node -v却提示找不到命令。根因sudo 默认环境会清掉当前用户的 PATH只保留一套最小化的系统路径。而 nvm 的 node 位于~/.nvm/versions/node/下不在系统路径里。同时nvm 本身是 shell 函数sudo 环境根本不加载你的 bashrc自然无从谈起。解决思路也简单避免在 sudo 环境里依赖 nvm需要提权执行某个 node 脚本时用绝对路径调用比如sudo $(which node) /path/to/script.js或者临时把用户 PATH 带进 sudosudo env PATH$PATH node -v顺便提醒一句尽量不要用 sudo 给 nvm 管理的 Node 安装全局包。每个版本目录都在用户目录下根本不需要 root。之前有人因为npm install -g权限报错就加 sudo结果包被装进系统目录污染了环境还碰到权限问题相当没必要。7.3 全局命令在新版本下“消失”现象切换 Node 版本后之前用npm install -g装的某个 CLI 工具再执行时提示 command not found。根因nvm 下每个 Node 版本的全局包独立存放。旧版本的全局包并没有迁移到新版本目录里。解法先列出旧版本里的全局包再决定要不要迁移nvm ls npm ls -g --depth0如果旧版本还在本地可以先把 default 切回旧版本导出清单再切到新版本安装。最省事的是nvm reinstall-packages但它只适合“当前版本与目标版本都来自 nvm 管理目录”的情况。如果旧全局包是系统装的老版本就别指望这条命令能帮你迁移。7.4 安装 Node 时下载卡住或校验和报错现象执行nvm install 23后卡在下载阶段很久不动或者下载完成后报 checksum 相关错误。根因大概率是下载通道不通畅或者镜像与官方文件不一致。nvm 下载 Node 二进制时对文件校验比较严格一旦镜像站同步不完整或者设置了错误的镜像地址就会报校验和不匹配。排查方法检查当前 shell 是否设置了NVM_NODEJS_ORG_MIRRORecho $NVM_NODEJS_ORG_MIRROR如果设置过试着手动在浏览器或 curl 里打开这个镜像路径确认里面的文件列表和官方结构一致。如果镜像配置无误可能是~/.nvm/.cache下残留了坏文件清掉缓存再试rm -rf ~/.nvm/.cache/bin然后重新执行nvm install 23。多数情况下校验和问题在清理缓存或者换一个同步正常的镜像后即可解决。最后再分享一个我自己的习惯升级完成后不要急着卸载旧版本。我会保留上一版至少一个月等新版本在实际项目中跑过各种场景、确认没有 ABI 兼容问题之后再删。删除命令是nvm uninstall 旧版本号同样不会碰系统目录。留着旧版本不是为了“万一不行”而是为了排查问题时有退路。Node 升级这件事最怕的不是升级失败而是升级之后不知道怎么回去。nvm 把“回去”变成了三个单词的事这已经是一种很踏实的体验了。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →