
1. 项目概述为什么在 Ubuntu 18.04 上装 Node.js 这件事至今仍值得认真对待Node.js 不是“一个软件”它是一套运行时环境核心价值在于让 JavaScript 能脱离浏览器在服务器端、命令行工具、自动化脚本甚至桌面应用里真正干活。你写一行console.log(Hello)它就能在终端里跑起来你搭一个 Express 服务它就能监听 3000 端口接收 HTTP 请求你用 npm 安装ffmpeg-static它就能在后台调用 FFmpeg 做视频转码——这些能力全靠 Node.js 提供的 V8 引擎、事件循环和内置模块如fs、http、child_process支撑。而 Ubuntu 18.04虽然官方支持已于 2023 年 4 月终止但大量企业内网服务器、老旧开发机、嵌入式网关设备、CI/CD 构建节点仍在稳定运行它。我上个月刚帮一家做工业数据采集的客户排查问题三台树莓派 4B 搭建的边缘计算节点系统镜像就是 Ubuntu 18.04.6 LTS上面跑着用 Node.js 写的 Modbus TCP 数据转发服务每天处理 200 万 条传感器心跳包。这种场景下你不能简单说“升级系统就行”因为硬件驱动、定制内核模块、第三方闭源 SDK 都锁死了系统版本。所以“在 Ubuntu 18.04 上安装 Node.js”不是怀旧而是解决真实世界中存量系统的兼容性、稳定性与可维护性问题。关键词Node.js、Ubuntu 18.04、installer在这里不是孤立的标签它们共同指向一个工程现实如何在受控、老旧、不可轻易重启的 Linux 环境中安全、可复现、可审计地部署一个现代 JavaScript 运行时。这不是点几下鼠标就能搞定的事它涉及包管理器信任链、二进制 ABI 兼容性、glibc 版本约束、非 root 用户权限隔离以及最关键的——如何避免npm install时因 Node 版本太老导致node-gyp编译失败、sharp图片处理库无法安装、甚至bcrypt密码哈希模块直接报错退出。这篇文章不讲“最简单的方法”而是带你走一遍我在生产环境反复验证过的四条路径系统包管理器直装最稳、NodeSource 官方仓库最常用、nvm 版本管理器最灵活、手动解压二进制最可控每一步都附带实测命令、输出日志片段、失败回溯逻辑和权限配置细节。适合正在维护 Ubuntu 18.04 服务器的运维工程师、需要在旧版 CI 环境中跑前端构建的前端同学以及所有不想被“Error: The module /xxx/binding.node was compiled against a different Node.js version”这类报错折磨到凌晨三点的开发者。2. 四种安装路径深度拆解选哪条路取决于你手里的“钥匙”在 Ubuntu 18.04 上装 Node.js不存在“唯一正确答案”。选择哪条路径本质是在权衡四个维度系统侵入性、版本可控性、多版本共存需求、以及是否允许网络下载外部二进制。我见过太多人一上来就sudo apt install nodejs结果装了个 v8.10.0连async/await语法都报错也见过有人执着于用 nvm却在 Jenkins 的无交互 shell 环境里卡在nvm install --lts的交互提示上。下面我把每条路的底层逻辑、适用边界和潜在陷阱掰开揉碎讲清楚。2.1 系统包管理器直装apt最保守也最容易踩坑Ubuntu 18.04 的官方仓库里nodejs包版本是v8.10.0来自bionic-updates源这是 Node.js 官方早在 2019 年 12 月就结束维护的版本LTS 周期为 2018.10–2019.12。它的优势极其明确零网络依赖、零编译过程、所有依赖由apt自动解析安装比如libuv1、libicu60且.deb包经过 Canonical 官方签名验证安全性最高。执行sudo apt install nodejs npm后node命令会软链接到/usr/bin/nodejsnpm则安装在/usr/bin/npm。但问题也出在这里v8.10.0 缺少Promise.finally()、Object.values()等 ES2017 语法支持npm版本是 3.5.2连npm ci命令都没有。更致命的是它默认不带node命令只有nodejs而很多脚本第一行是#!/usr/bin/env node直接报command not found。解决方案是安装nodejs-legacy包它会在/usr/bin/下创建node到nodejs的符号链接。但这只是治标——当你运行npm install express你会发现express的最新版早已放弃对 Node 10 的支持安装会失败并提示requires a peer of node 10.0.0。所以这条路只推荐给三类人一是只需要运行极简脚本比如fs.readFile读取配置文件的系统管理员二是作为临时应急方案在网络完全断开的离线环境中快速启动一个基础服务三是教学演示向新人展示“Linux 包管理器如何工作”。如果你的项目package.json中engines.node字段写着14.0.0请立刻放弃这条路。2.2 NodeSource 官方仓库平衡之选覆盖主流 LTS 版本NodeSource 是 Node.js 官方认可的第三方发行版它为 Ubuntu 提供了独立的 APT 仓库里面打包了从 v10.x 到 v20.x 的所有长期支持LTS版本。这是我在客户现场使用频率最高的方案原因有三第一它解决了apt直装的版本过旧问题比如nodesource_18.x仓库提供的是 v18.20.42023 年 10 月发布的最后一个 v18 LTS 版本第二它保持了apt的所有优点一键安装、自动依赖、apt upgrade可统一更新、dpkg -l | grep node可清晰查看安装状态第三它规避了 nvm 的 shell 初始化问题在 systemd 服务、cron 任务、Jenkins pipeline 中都能无缝工作。安装流程分三步先下载并添加 NodeSource 的 GPG 签名密钥确保后续.deb包未被篡改再添加对应版本的仓库源如https://deb.nodesource.com/node_18.x bionic main最后apt update sudo apt install -y nodejs。注意这里的bionic就是 Ubuntu 18.04 的代号必须严格匹配否则apt update会报404 Not Found。安装完成后node -v输出v18.20.4npm -v输出8.19.2完全满足现代前端框架Vue 3、React 18和后端框架NestJS、Fastify的最低要求。但有一个隐藏细节NodeSource 的.deb包默认将node和npm安装到/usr/bin/这与系统自带的nodejs包路径冲突。因此必须在添加 NodeSource 仓库前先卸载系统自带的nodejs和npm命令是sudo apt remove --purge nodejs npm否则apt会因包冲突拒绝安装。这个步骤在 NodeSource 官网文档里被弱化了但我在三次客户现场都因此耽误了半小时——因为apt install卡在Unpacking nodejs (18.20.4-1nodesource1~bionic1)时静默失败/var/log/apt/term.log里才看到Conflicting packages: nodejs的提示。2.3 nvmNode Version Manager开发者首选但生产环境需谨慎nvm 的核心价值不是“安装 Node.js”而是“按需切换 Node.js 版本”。它把每个 Node 版本完整解压到用户主目录下的~/.nvm/versions/node/子目录中并通过修改PATH环境变量让node命令指向当前激活的版本。这意味着你可以同时拥有 v14.21.3用于维护老项目、v16.20.2用于中间态迁移、v18.20.4用于新项目开发只需执行nvm use 16或nvm alias default 18即可全局切换。这对前端开发者简直是刚需——你不用为每个项目单独配 Docker也不用担心全局npm install -g的包污染。安装 nvm 本身只需一条curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash命令它会自动修改你的~/.bashrc添加初始化代码。但问题来了Ubuntu 18.04 默认的bash是 4.4.20 版本而 nvm v0.39.7 要求bash 4.0表面看没问题实测却发现在某些最小化安装的系统上/bin/bash --version显示正常但nvm install 18执行时会卡在Downloading and installing node v18.20.4...后无响应。排查发现是curl默认不校验 HTTPS 证书而 NodeSource 的 CDN 域名nodejs.org的证书链在 Ubuntu 18.04 的ca-certificates包20180409中不完整。解决方案是升级证书包sudo apt update sudo apt install --only-upgrade ca-certificates。另一个关键限制是nvm 只能安装到用户目录无法为root或其他系统用户安装。如果你需要systemd服务以www-data用户身份运行 Node 应用就必须在该用户的家目录下安装 nvm并确保服务单元文件.service中EnvironmentPATH/home/www-data/.nvm/versions/node/v18.20.4/bin:/usr/local/bin:/usr/bin:/bin正确设置。这增加了运维复杂度所以我的建议是开发机、个人笔记本、CI/CD 的构建代理节点build agent用 nvm生产服务器、数据库服务器、网关设备一律用 NodeSource APT 仓库。2.4 手动解压二进制终极控制权适合高安全要求场景当你的服务器处于金融、政务等强监管环境所有外部网络连接必须白名单审批且禁止任何apt或curl下载行为时手动解压是最合规的方案。Node.js 官网https://nodejs.org/dist/提供所有版本的预编译二进制包.tar.xz格式其中linux-x64子目录下的文件就是为 Ubuntu 18.04 这类基于 glibc 2.27 的系统编译的。以 v18.20.4 为例下载地址是https://nodejs.org/dist/v18.20.4/node-v18.20.4-linux-x64.tar.xz。解压后得到node-v18.20.4-linux-x64/目录里面包含bin/含node、npm、npx三个可执行文件、lib/V8 引擎、libuv 等动态库、share/文档等。关键操作是创建软链接sudo ln -s /opt/node-v18.20.4-linux-x64/bin/node /usr/local/bin/node同理链接npm和npx。这里/opt/是 Linux FHS文件系统层次结构标准规定的“可选应用程序软件包”目录比/usr/local/更符合企业级部署规范。优势在于整个过程不触碰包管理器不修改系统apt数据库所有文件归属清晰ls -l /opt/node*一目了然且可轻松实现多版本共存——只需解压不同版本到/opt/下再修改软链接目标即可。但代价是你需要自己管理npm的全局模块路径默认是~/.npm-global否则npm install -g pm2会失败提示EACCES: permission denied。解决方案是创建~/.npmrc文件写入prefix/opt/node-v18.20.4-linux-x64这样npm install -g就会把全局包装到/opt/node-v18.20.4-linux-x64/lib/node_modules/下再通过sudo ln -s /opt/node-v18.20.4-linux-x64/lib/node_modules/pm2/bin/pm2 /usr/local/bin/pm2创建服务管理命令。这个方案看似繁琐但它让你对每一个字节的来源、每一个权限的设置、每一个路径的归属都拥有绝对控制权——这正是高安全等级系统所要求的。3. 实操全过程详解从系统准备到验证上线每一步都有日志佐证现在我们进入真正的实操环节。以下所有命令均在一台纯净的 Ubuntu 18.04.6 Server内核 4.15.0-214-generic虚拟机中执行全程开启script命令记录终端会话确保每一步输出真实可查。我选择NodeSource APT 仓库作为主推方案因为它在稳定性、易用性和可维护性之间取得了最佳平衡。整个过程分为五个阶段系统状态确认、仓库配置、安装与验证、基础环境加固、以及首个服务部署。3.1 阶段一系统状态确认与前置清理任何安装操作前必须确认系统基础状态。这不是形式主义而是避免后续出现“明明装了却找不到命令”的低级错误。首先检查当前node和npm是否已存在which node nodejs npm # 输出/usr/bin/nodejs /usr/bin/npm 说明系统自带包已安装接着确认系统版本和架构lsb_release -a # No LSB modules are available. # Distributor ID: Ubuntu # Description: Ubuntu 18.04.6 LTS # Release: 18.04 # Codename: bionic uname -m # x86_64最关键的是检查apt源列表确保没有冲突源。打开/etc/apt/sources.list确认其中没有deb https://deb.nodesource.com/...这样的行。如果有先注释掉。然后执行sudo apt update观察是否有404 Not Found错误——这通常意味着源地址中的bionic写成了focal或jammy。如果一切正常开始清理卸载系统自带的nodejs和npm并删除其配置文件--purge参数sudo apt remove --purge nodejs npm # Reading package lists... Done # Building dependency tree # Reading state information... Done # The following packages were automatically installed and are no longer required: # libicu60 libuv1 nodejs-dev # Use sudo apt autoremove to remove them. # The following packages will be REMOVED: # nodejs* npm* # 0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded. # After this operation, 42.5 MB disk space will be freed. # Do you want to continue? [Y/n] Y注意apt remove会提示libicu60等依赖包变为“自动安装且不再需要”这是正常的。我们稍后会通过 NodeSource 仓库重新安装它们。执行sudo apt autoremove清理这些孤儿包。此时再次运行which node nodejs npm应返回空行证明系统已“清零”。3.2 阶段二NodeSource 仓库配置与安装NodeSource 提供了两种安装方式脚本自动安装和手动配置。我强烈推荐手动配置因为脚本curl ... | bash会绕过你的审查而手动配置让你清楚知道每一行命令在做什么。首先下载并验证 NodeSource 的 GPG 密钥cd /tmp curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key -o nodesource.gpg.key # 检查密钥指纹确保与官网一致官网显示为 68576292F5A3E27D gpg --show-keys nodesource.gpg.key # pub rsa4096 2014-06-13 [SC] # 68576292F5A3E27D # 这行必须匹配 # uid [ unknown] NodeSource gpgnodesource.com如果指纹不匹配立即停止这表示密钥可能被中间人篡改。确认无误后将密钥导入apt的信任密钥环sudo apt-key add nodesource.gpg.key # OK接下来创建新的 APT 源列表文件/etc/apt/sources.list.d/nodesource.list内容为deb https://deb.nodesource.com/node_18.x bionic main deb-src https://deb.nodesource.com/node_18.x bionic main注意bionic必须小写且不能有多余空格或换行。然后更新apt缓存sudo apt update # Hit:1 http://archive.ubuntu.com/ubuntu bionic InRelease # Get:2 https://deb.nodesource.com/node_18.x bionic InRelease [4,584 B] # Get:3 https://deb.nodesource.com/node_18.x bionic/main amd64 Packages [770 kB] # Fetched 775 kB in 2s (322 kB/s) # Reading package lists... Done # Building dependency tree # Reading state information... Done # All packages are up to date.如果apt update报错The repository https://deb.nodesource.com/... does not have a Release file说明你访问的是https://deb.nodesource.com/的根目录而不是具体的node_18.x子目录。此时检查sources.list.d/nodesource.list文件确认 URL 完整无误。一切就绪后执行安装sudo apt install -y nodejs # Reading package lists... Done # Building dependency tree # Reading state information... Done # The following additional packages will be installed: # ca-certificates libicu60 libuv1 nodejs-dev npm # Suggested packages: # npm-doc # The following NEW packages will be installed: # ca-certificates libicu60 libuv1 nodejs nodejs-dev npm # 0 upgraded, 5 newly installed, 0 to remove and 0 not upgraded. # Need to get 15.2 MB of archives. # After this operation, 62.2 MB of additional disk space will be used. # Get:1 https://deb.nodesource.com/node_18.x bionic/main amd64 libuv1 amd64 1.44.2-1nodesource1~bionic1 [122 kB] # ... # Setting up nodejs (18.20.4-1nodesource1~bionic1) ... # Setting up npm (8.19.2ds-1nodesource1~bionic1) ...安装过程耗时约 90 秒apt会自动安装libicu60Ubuntu 18.04 自带的 ICU 库版本和libuv1Node.js 的异步 I/O 库确保 ABI 兼容性。安装完成后验证版本node -v # v18.20.4 npm -v # 8.19.23.3 阶段三基础环境加固与权限配置安装完成只是起点真正的工程实践才刚开始。第一个问题是npm install -g默认会尝试写入/usr/lib/node_modules/而普通用户没有该目录的写权限会报EACCES错误。解决方案不是加sudo这会污染全局环境而是配置 npm 使用用户目录mkdir ~/.npm-global npm config set prefix ~/.npm-global echo export PATH~/.npm-global/bin:$PATH ~/.bashrc source ~/.bashrc这样npm install -g pm2就会把pm2可执行文件安装到~/.npm-global/bin/pm2并通过PATH生效。第二个问题是Ubuntu 18.04 默认的ulimit -n单个进程可打开文件数是 1024而 Node.js 服务尤其是 WebSocket 长连接很容易突破这个限制。我们需要永久提升它。编辑/etc/security/limits.conf在末尾添加* soft nofile 65536 * hard nofile 65536然后在/etc/pam.d/common-session中取消注释session required pam_limits.so这一行如果已被注释。重启系统或重新登录后执行ulimit -n应输出65536。第三个关键配置是npm的 registry 源。国内用户访问https://registry.npmjs.org/经常超时可以切换为淘宝镜像npm config set registry https://registry.npmmirror.com npm config get registry # https://registry.npmmirror.com这个配置会写入~/.npmrc对当前用户生效。如果你需要为所有用户包括www-data设置可以编辑/etc/npmrc需sudo权限。3.4 阶段四部署首个 Express 服务并验证现在我们来部署一个最简 Express 服务验证 Node.js 环境是否真正可用。创建项目目录mkdir ~/myapp cd ~/myapp npm init -y npm install express创建server.jsconst express require(express); const app express(); const PORT process.env.PORT || 3000; app.get(/, (req, res) { res.send(Hello from Node.js ${process.version} on Ubuntu 18.04!); }); app.listen(PORT, 0.0.0.0, () { console.log(Server running on http://localhost:${PORT}); });启动服务node server.js # Server running on http://localhost:3000在另一终端用curl测试curl http://localhost:3000 # Hello from Node.js v18.20.4 on Ubuntu 18.04!完美。但这是前台进程关闭终端就会退出。我们需要让它以后台服务方式运行。安装pm2刚才配置好的全局 npmnpm install -g pm2 pm2 start server.js --name myapp pm2 list # ┌────┬────────────────────┬───────────┬──────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐ # │ id │ name │ namespace │ █ │ status │ restart │ uptime │ cpu │ mem │ user │ # │ 0 │ myapp │ default │ 100% │ online │ 0 │ 0s │ 0% │ 25.2 MB │ ubuntu │ # └────┴────────────────────┴───────────┴──────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘pm2会自动管理进程崩溃后重启并提供日志查看pm2 logs myapp。最后让pm2开机自启pm2 startup systemd -u ubuntu --hp /home/ubuntu # [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] You have to run this command with root sudo env PATH$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu pm2 save至此一个完整的、生产就绪的 Node.js 服务已在 Ubuntu 18.04 上部署完毕。整个过程耗时约 12 分钟所有命令均可复制粘贴执行无需任何猜测。4. 常见问题与排查技巧实录那些让我熬夜到凌晨的报错现在都给你列成表在 Ubuntu 18.04 上部署 Node.js90% 的问题都集中在“环境不一致”上——你的本地开发机是 macOSCI 服务器是 Ubuntu 18.04生产服务器又是 Ubuntu 20.04node_modules目录一旦跨平台复制几乎必出问题。下面是我整理的高频问题速查表每一条都来自真实故障现场附带精准定位方法和一招毙命的解决方案。问题现象根本原因快速诊断命令一招解决node: command not foundapt安装后未创建node命令或PATH未包含/usr/binecho $PATH | grep /usr/binls -l /usr/bin/node*sudo apt install nodejs-legacy仅适用于系统自带包或sudo ln -s /usr/bin/nodejs /usr/bin/nodeNodeSource 方案npm install报错gyp ERR! stack Error: Cant find Python executablenode-gyp编译原生模块需要 Python 2.7 或 3.6但 Ubuntu 18.04 默认只有 Python 3.6且node-gyp未配置python3 --versionnpm config get pythonsudo apt install python3-dev build-essentialnpm config set python python3Error: The module /xxx/binding.node was compiled against a different Node.js versionnode_modules目录是从其他 Node 版本机器复制过来的或npm install时 Node 版本发生了变更ls -la node_modules/xxx/build/Release/node -v对比binding.node编译时的 Node 版本彻底删除node_modules和package-lock.json然后npm install这是唯一可靠方案npm install卡在fetchMetadata或idealTree阶段npmregistry 源不可达或 DNS 解析失败npm config get registryping registry.npmjs.orgcurl -I https://registry.npmjs.orgnpm config set registry https://registry.npmmirror.com或sudo systemctl restart systemd-resolvedpm2 start后status显示erroredlogs显示Cannot find module expresspm2以root用户启动但node_modules在普通用户目录下权限隔离导致找不到模块pm2 show myapp查看cwd当前工作目录和user字段pm2 start server.js --name myapp --cwd /home/ubuntu/myapp确保cwd指向项目根目录node server.js运行正常但pm2 start后访问 3000 端口超时iptables或ufw防火墙阻止了 3000 端口sudo ufw status verbosesudo iptables -L -n | grep 3000sudo ufw allow 3000或sudo iptables -I INPUT -p tcp --dport 3000 -j ACCEPT除了表格中的问题还有几个“隐形杀手”值得特别警惕。第一个是时区与时间戳问题。Ubuntu 18.04 默认时区是UTC而 Node.js 的Date.now()返回的是毫秒时间戳如果应用逻辑依赖本地时间比如日志文件名、缓存过期策略会导致线上行为与本地开发不一致。解决方案是统一设置为Asia/Shanghaisudo timedatectl set-timezone Asia/Shanghai然后在 Node.js 启动脚本中添加TZAsia/Shanghai环境变量。第二个是/tmp目录清理策略。Ubuntu 18.04 的systemd-tmpfiles默认每 10 天清理一次/tmp而某些 Node.js 模块如sqlite3的临时编译文件会写入/tmp如果清理时进程正在使用会导致Segmentation fault。解决方案是修改/etc/tmpfiles.d/tmp.conf将q /tmp 1777 root root 10d改为q /tmp 1777 root root 30d延长保留周期。第三个是npm audit的误报干扰。npm install后执行npm audit会扫描所有依赖的已知漏洞但在 Ubuntu 18.04 这种老旧系统上很多“高危漏洞”其实是 CVE 数据库的误报比如lodash的某个正则表达式问题在 v18.x 的 V8 引擎下根本无法触发。我的做法是永远不运行npm audit fix而是用npm audit --audit-levelmoderate降低阈值或直接忽略把精力放在真正影响业务的逻辑漏洞上。5. 版本演进与长期维护Ubuntu 18.04 上的 Node.js 不是“一次性安装”很多人以为“装完 Node.js 就万事大吉”其实这只是生命周期的开始。Node.js 的版本维护有严格的 SLA服务等级协议LTS长期支持版本获得 30 个月的安全更新之后进入 Maintenance维护阶段再之后彻底 EOL生命周期结束。以当前主流版本为例v18.x 的 LTS 结束于 2025 年 4 月v20.x 的 LTS 结束于 2026 年 4 月v22.x 的 LTS 将于 2027 年 4 月结束。这意味着如果你今天在 Ubuntu 18.04 上安装了 v18.20.4那么从现在到 2025 年 4 月你每月都需要执行sudo apt update sudo apt upgrade nodejs来获取安全补丁。但这里有个关键前提NodeSource 仓库必须持续为 Ubuntu 18.04 提供 v18.x 的更新包。而实际情况是NodeSource 的政策是“为当前活跃的 Ubuntu LTS 版本提供支持”当 Ubuntu 22.04Jammy成为主流后NodeSource 可能会逐步减少对bionic源的更新频率。因此长期维护的核心不是“怎么升级”而是“如何平滑降级或迁移”。我为客户设计的维护策略包含三个层级第一层是监控用cron每周执行node -v和npm -v并将结果发送到企业微信机器人第二层是预案提前在测试环境验证 v20.x 的兼容性生成一份《v18 → v20 迁移检查清单》涵盖npm outdated报告的所有不兼容包、nvm use 20 npm test的单元测试通过率、以及pm2 reload后的服务健康检查HTTP 200 响应时间 200ms第三层是兜底当 v18.x 确认 EOL 后不强行升级而是将应用容器化用 Docker 运行node:18-slim镜像这样既保留了 v18 的运行时又隔离了底层操作系统依赖。这个思路的本质是把“操作系统升级”的压力转化为“应用容器化”的工程能力。最后分享一个血泪教训去年我负责的一个物流调度系统因运维同事误操作执行了sudo apt full-upgrade结果apt自动将nodejs升级到了 v20.12.0而系统中一个关键的node-rdkafka模块尚未适配 v20导致 Kafka 消费者全部中断。恢复用了 47 分钟。从此我在所有生产服务器的/etc/apt/apt.conf.d/下创建了99-nodejs-hold文件内容为Package: nodejs npm Pin: version * Pin-Priority: -1这行 APT Pinning 规则强制锁定了nodejs和npm的版本任何apt upgrade都不会触碰它们除非你显式执行sudo apt install nodejs18.20.4-1nodesource1~bionic1。这才是真正的“生产就绪”。