SSD Nodes Learn Hosting plans →
指南 Matt Connor作者: Matt Connor · 更新于 2026-10-25

Ubuntu 升级中途失败如何恢复?修复指南

Ubuntu 24.04 升级 26.04 失败后不要直接重启。本指南教你如何通过 screen 恢复会话、修复 dpkg 中断错误、处理软件源冲突,并判断何时应通过快照回滚系统以避免彻底崩溃。

Ubuntu 升级中途失败:首先排查故障现象

从 24.04 升级到 26.04 的 Ubuntu 版本升级失败后,服务器会处于四种状态之一,每种状态的修复方法各不相同。升级程序可能仍在某个你已断开连接的 screen 会话中运行。dpkg 可能因软件包配置中断而被终止,导致 apt 现在拒绝执行任何安装、删除或升级软件包的操作,尽管 apt update 可以运行,且 apt show 等只读命令也能正常执行。apt 源可能已指向 26.04,但已安装的软件包仍为 24.04 版本。或者,服务器可能完全无法启动。在输入任何命令前,请先确定你处于哪种状态,因为针对某种状态的修复操作可能会使另一种状态恶化。

有一条规则适用于所有四种情况。在确认 dpkg 的状态之前,请勿重启。在软件包替换过程中重启,会将可修复的 dpkg 中断转变为本指南末尾提到的无法启动的情况。此外,当第一个 apt 或 dpkg 进程可能仍在运行时,请勿启动第二个进程,因为两个进程同时写入软件包数据库会导致数据库损坏。

本指南假设你已遵循 24.04 到 26.04 升级指南 并在开始前创建了快照。如果你没有创建快照,请在阅读启动故障章节时注意这一点,因为快照是解决最坏情况的方案。

升级程序还在运行吗?

许多被报告为失败的升级实际上仍在运行。SSH 会话断开,终端变为空白,而升级程序在没有您参与的情况下继续运行。

do-release-upgrade 正是为此设计的。当它在服务器默认的文本界面下运行时,会自动封装在一个 GNU screen 会话中,因此即使启动它的终端丢失,升级过程依然能够存活。此外,当它检测到是从 SSH 会话启动时,会主动提供在另一个端口(默认 1022)启动第二个 sshd 的选项,以便在软件包替换期间主 SSH 守护进程崩溃时,您仍能登录。这两个事实在此刻至关重要。

重新通过 SSH 连接并查找 screen 会话。升级程序在 sudo 下运行,因此其 screen 会话归 root 用户所有,以普通用户身份执行 screen -ls 将无法列出该会话。

sudo screen -ls

screen -ls 会标记每个会话是已连接(attached)还是已断开(detached)。如果列出了会话,请重新连接到它。如果由于死掉的 SSH 连接未释放而显示为已连接,请先使用 -d 强制断开该过期的连接。

sudo screen -d -r

如果列出了多个会话,请在 -r 后加上 screen -ls 中的会话名称。不要指望 sudo do-release-upgrade 能自动为您重新连接。查找现有 screen 会话的代码位于升级程序下载的脚本中,而在下载任何内容之前,如果发现有待更新的软件包(分阶段更新除外),do-release-upgrade 会直接退出并提示“请在升级前安装当前版本的所有可用更新”,这正是系统处于软件包替换中途时的状态。重新连接后,您将回到正在运行的升级进程中,它通常正停留在关于配置文件变更或服务重启的提示符处。回答提示并让其完成即可。

如果您按照升级指南的建议在 tmux 中启动了升级,请先使用 tmux attach 重新连接 tmux。screen 会话运行在该 tmux 面板内,因此您可以直接看到升级进度。如果面板中仅显示 shell 提示符,说明升级程序已不在那里运行,此时应执行 sudo screen -ls 进行下一步检查。

如果主 SSH 端口拒绝连接,请尝试备用端口:ssh -p 1022 user@host。该守护进程仅在升级期间存在,因此如果两个端口都无法进入,请使用服务商提供的控制台。在控制台中,sudo ss -ltnp 可以显示 sshd 进程正在监听哪些端口,sudo ufw status 可以确认防火墙是否放行了备用端口。

当不存在 screen 会话且控制台也没有任何等待响应的提示时,说明升级确实已经停止。在操作软件包数据库之前,请确认没有任何进程仍在运行:

ps -eo pid,etime,cmd | grep -iE '[u]pgrade|[d]pkg|[a]pt'

如果结果为空,说明 dpkg 处于空闲状态,您可以继续进行修复。如果 dpkg 或 apt 进程运行时间很长且没有可重新连接的 screen 会话,说明它已挂起。请等待几分钟,检查控制台是否有无人响应的 debconf 问题,确认后再将其终止。在进程持有锁文件时,切勿删除 /var/lib/dpkg/ 或 /var/lib/apt/lists/ 下的锁文件。该锁是防止两个写入进程同时破坏软件包数据库的唯一机制。

dpkg 中断,apt 拒绝运行

如果在解压软件包和运行其配置脚本之间终止 dpkg,该软件包会被标记为未完成状态,并在 /var/lib/dpkg/updates/ 下的日志中留下未完成的条目。所有会获取 dpkg 锁的 apt 命令,也就是安装、删除或升级软件包的命令,都会先检查该日志,然后以 dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem. 停止。不获取该锁的命令,例如 apt update、apt list、apt show 和 apt-cache,仍可正常运行,因此您仍然可以查看系统状态。无论 apt 还输出什么内容,第一步都相同。

sudo dpkg --configure -a

这会完成所有已解压但尚未配置的软件包的配置步骤。该命令会按依赖顺序运行维护者脚本。在部分升级的系统上,这可能需要很长时间,因此在命令返回前不要中断它。如果命令在某个软件包处停止,它会输出软件包名称和失败的脚本。记下该名称。它就是阻止升级的软件包,下一节将说明如何读取其错误信息。

然后让 apt 修复中断留下的未满足依赖,因为部分软件包已升级,但它们所依赖的软件包尚未升级。

sudo apt --fix-broken install

然后完成升级程序正在执行的升级:

sudo apt update
sudo apt full-upgrade

请使用 full-upgrade,而不是 upgrade,因为发行版升级会删除软件包,而普通的 upgrade 会拒绝删除任何内容。确认前先阅读 apt 输出的摘要。删除少量软件包通常是正常的。但如果列表中包含 ubuntu-server、systemd、openssh-server 或内核软件包,则不正常。此时应选择否,并先查明 apt 为什么要删除这些软件包。

在执行其他操作前检查结果:

sudo dpkg --audit
sudo apt-get check

dpkg --audit 会列出所有仍处于损坏状态的软件包,apt-get check 会报告未满足的依赖。两者都应不输出任何内容。如果有输出,请运行 sudo apt autoremove,删除当前不再需要的自动安装依赖(标记为手动安装的软件包会保留,即使没有任何软件包使用它们),然后使用 cat /etc/os-release 确认发行版,再运行 sudo update-initramfs -u -k all 和 sudo update-grub,最后才能重启。

如何读取 /var/log/dist-upgrade 以找出阻止升级的软件包

升级程序会将所有内容写入 /var/log/dist-upgrade/。如果运行过多次,它会将之前尝试的日志移入以时间戳命名的子目录,因此请先检查 ls -la /var/log/dist-upgrade/,然后读取与失败运行相对应的目录。

main.log 是升级程序自己的日志。它记录运行所处的阶段,以及升级程序如何处理软件源。如果升级程序本身崩溃,Python 回溯也会记录在这里。请从末尾开始读取:最后几行会告诉您它停止时所处的阶段。如果末尾有回溯,说明失败的是工具,而不是软件包。

apt.log 保存依赖解析器的判断过程。内容较多,但当 apt 根本拒绝计算升级方案时很有用,因为这表示在处理任何软件包前就已经失败。如果升级已经进行到安装软件包的阶段,通常可以跳过此文件。

apt-term.log 是排查软件包失败时需要查看的文件。它会记录升级期间 dpkg 的终端输出,也就是原本会滚过屏幕的相同内容。文件末尾之前最后提到的软件包,就是升级停止时正在处理的软件包。如果维护者脚本失败,dpkg 对该脚本的报错,以及脚本上方紧邻的脚本自身错误,都会记录在这里。

sudo tail -n 60 /var/log/dist-upgrade/apt-term.log
sudo grep -in 'error' /var/log/dist-upgrade/apt-term.log | tail

请与 /var/log/dpkg.log 交叉核对。该文件会记录 dpkg 执行的状态更改和操作,并为每项操作标记时间戳。tail -n 30 /var/log/dpkg.log 显示 dpkg 最后处理的软件包,以及当时对它执行的操作。只有在失败后没有再次运行 dpkg 时,这才是来自第二个来源的相同结论。运行 dpkg --configure -a 或 apt --fix-broken install 后,它们的条目会出现在末尾,因此请向上滚动,查找升级停止时对应时间戳的行。

服务器在此阶段发生的多数失败都来自少数几类原因。软件包会在 postinst 中重启某项服务,但该服务因您自定义的配置文件而无法启动;此时,该服务的 systemctl status 和 journalctl -xeu 会指出它不接受的配置行。磁盘已满,最常见的是 /boot 被旧内核占满,或 /var 被 apt 的软件包缓存占满;df -h / /boot /var 会显示相关信息。即使 apt 处于其他故障状态,sudo apt clean 仍可清空缓存;du 显示未满但磁盘报告已满 的情况另有解释。升级程序禁用的第三方软件源中的某个软件包,依赖一个 26.04 不再发布的库。被保持的软件包(apt-mark showhold)阻止了某项依赖升级。修复原因后,再次运行 sudo dpkg --configure -a。它会从停止的位置继续。

如果无论如何都无法配置某个软件包,且没有重要软件包依赖它,请将其删除,并在升级完成后重新安装:

sudo dpkg --remove --force-remove-reinstreq package-name
sudo dpkg --configure -a

只能对您能够明确说明名称和问题的软件包使用此命令。不要对库或 ubuntu-server 依赖链中的任何内容使用它,因为强制删除会跳过检查,而这些检查本可以告知您还会破坏哪些内容。

源已切换,但软件包未切换

升级程序会在下载任何软件包之前,提前重写 APT 源。此后如果升级被中断,源会指向 26.04,但已安装的软件包仍处于混合状态。这种混合状态会使工具无法正确判断,因此 do-release-upgrade 现在可能会坚持认为没有新版本可用。

请比较以下两个位置,它们分别说明当前使用的版本。/etc/apt/sources.list.d/ubuntu.sources 是 24.04 引入的 deb822 源文件,其中的 Suites: 行包含版本代号。/etc/os-release 由 base-files 软件包写入,用于说明实际安装的版本。

grep -E '^(Suites|Components):' /etc/apt/sources.list.d/ubuntu.sources
grep -E '^(VERSION_ID|VERSION_CODENAME)=' /etc/os-release
apt-cache policy base-files

有 3 种组合需要关注。源仍指向 24.04(代号为 noble),而 os-release 仍说明版本为 24.04:升级尚未通过检查。阅读 main.log 以了解停止原因,然后可以再次运行 sudo do-release-upgrade。如果仍有任何 24.04 更新待处理,或 /var/run/reboot-required.pkgs 指向 libc6、linux-base 或某个 linux-image 软件包,升级程序就不会启动。因此请运行 sudo apt full-upgrade;如果该文件要求先重启,请执行重启。

源指向 26.04 的版本代号,而 os-release 仍说明版本为 24.04:软件包替换已经开始,但被中断。上一节介绍的 dpkg 修复流程,以 apt full-upgrade 结束,是完成升级的方法。在此状态下不要重新运行升级程序;由于有 26.04 软件包等待安装,它会停止并要求先安装所有可用更新。

源指向 26.04,而 os-release 也说明版本为 26.04:base-files 是已完成安装的软件包之一。系统现在会将自身识别为 26.04,即使大多数软件包实际上尚未完成升级。

最后一种组合最容易导致误判。do-release-upgrade 根据与 os-release 相同的信息判断当前版本。如果该文件已经说明版本为 26.04,工具接下来报告的内容取决于 /etc/update-manager/release-upgrades 中的 Prompt= 行。在 Prompt=lts 模式下,这是 26.04 的默认设置。工具会查找比 26.04 更新的 LTS 版本,但找不到,因此报告没有可用的新版本。

在 Prompt=normal 模式下,Canonical 发布的 26.10 公告称,26.04 用户将获得 26.10。2026 年 10 月 24 日检查时,Ubuntu 的版本升级元数据尚未列出 26.10,因此工具在当天仍报告没有可用的新版本;待 26.10 被列出后,工具会找到 26.10,然后因为仍有 24.04 软件包存在待处理升级而停止,并显示“请先为当前版本安装所有可用更新”。无论哪种情况,工具回答的都是关于 os-release 的问题,而 os-release 的内容是错误的。

不要继续询问升级程序,直接使用 apt 完成升级:先运行 sudo apt update,再运行 sudo apt full-upgrade。这会升级仍处于 24.04 版本的软件包,但处于 hold 状态的软件包除外(apt-mark showhold 可列出这些软件包)。该命令也可能改为删除部分软件包,因此请阅读摘要,然后运行 sudo apt autoremove。如果 os-release 仍说明版本为 24.04,还应排除do-release-upgrade 报告没有新版本的其他原因。LTS 提示要求等待第一个点版本的条件已不再适用:2026 年 10 月 24 日检查时,Ubuntu 的 LTS 升级元数据已将 26.04.1 列为受支持版本。

升级程序还会禁用 /etc/apt/sources.list.d/ 下的第三方源,并为每个修改过的文件保留备份副本,同时在原文件名后添加后缀。请运行 ls -la /etc/apt/sources.list.d/ 和 diff,分别将每个原文件与其备份进行比较,以准确查看升级程序执行的修改。Ubuntu 软件包恢复一致之前,请保持第三方源禁用。之后,只有确认供应商已发布适用于 26.04 的软件包,才重新启用对应的软件源。

如果 apt update 报告某个源被配置了多次,说明旧的 sources.list 条目和新的 ubuntu.sources 条目描述了同一个软件源套件。deb822 重复源错误会说明应删除哪一个条目。

升级后服务器无法启动

重启时,未完成的升级往往会暴露问题。在 VPS 上,常见原因包括:安装内核时未生成 initramfs、从未重新生成 GRUB 配置、某个启动时单元依赖的软件包处于未完成配置状态,或者 dpkg 写入数据时磁盘已满。

在进行其他操作前,先打开服务商的控制台。控制台会显示启动停止的位置:GRUB 菜单、内核崩溃、等待回答的文件系统检查,或要求输入 root 密码的 systemd emergency shell。这个判断决定下一步操作。

如果出现 GRUB,请从高级选项子菜单启动之前的 24.04 内核。旧内核通常会一直保留,直到 autoremove 运行。使用旧内核启动系统后,执行 sudo dpkg --configure -a,并按照上一节完成其余修复;然后执行 sudo update-initramfs -u -k all 和 sudo update-grub,再重新尝试启动新内核。修复内核更新后无法启动的 VPS详细介绍了 GRUB 和 initramfs 相关操作。

如果进入 emergency shell,root 文件系统通常以只读方式挂载。重新挂载后执行相同的修复操作:

mount -o remount,rw /
dpkg --configure -a

如果系统完全无法进入 shell,请启动服务商的救援镜像,挂载 VPS 磁盘,然后从 chroot 中修复。使用 lsblk 查找 root 分区,不要凭猜测确定分区名称。

lsblk
mount /dev/<root-partition> /mnt
for d in dev proc sys run; do mount --bind /$d /mnt/$d; done
chroot /mnt /bin/bash
dpkg --configure -a
apt --fix-broken install
update-initramfs -u -k all
update-grub
exit
reboot

在 chroot 中耗费一小时之前,先将其与快照恢复进行比较。你在开始操作前已经创建了快照,而大多数服务商只需几分钟即可完成恢复。之后重新运行升级;在 VPS 上通常不到一小时。这次你已经知道需要提前修复哪个软件包。满足以下任一条件时,恢复快照通常更快:无法访问控制台或救援镜像、无法确定导致升级停止的软件包、有多个软件包卡在未完成状态,或者服务器上运行着有人正在等待使用的服务。只有在你明确知道发生故障的唯一原因,并且修复只需执行一条命令时,手动修补才更快。

恢复前,将 /var/log/dist-upgrade/ 从服务器复制出来;如果只能通过救援镜像访问服务器,就从救援镜像中复制。恢复操作会删除这些日志。如果你没有找出第一次失败的原因,第二次尝试会完全重复同样的失败。依赖快照前,值得阅读快照可以恢复和无法恢复的内容。快照会将整个磁盘回滚,包括创建快照后写入的所有数据。升级过程中这样做通常没有问题,但一周后再这样做就可能造成数据丢失。

应改为重建系统的三个迹象

有些升级不值得继续修复。恢复快照并重新执行升级的成本很低,但如果故障源于系统本身的状态,第二次执行也会失败。此时,正确的做法是使用全新的 26.04 镜像,再从备份恢复数据。出现以下三个迹象时,就说明应当这样处理。

第一,dpkg 自身的数据库已损坏。如果 dpkg --audit 或 apt-get check 完全无法读取 /var/lib/dpkg/status,而不是报告其中存在损坏的软件包,那么已安装软件包的记录就丢失了。Ubuntu 会在 /var/backups/(ls -la /var/backups/dpkg.status*)下保存每日副本,将最新的可用副本替换到原位置有时可以解决问题。但如果该副本与磁盘上的实际状态不一致,后续操作就只能依靠猜测,而每次 apt 执行都会继续建立在这个猜测之上。

第二,修复系统所需的工具本身已损坏。如果 apt 或 dpkg 因共享库被删除或部分替换而无法启动,或者 systemd 因自身的软件包处于半配置状态而无法启动单元,那么系统中就没有可用的软件包管理器来修复软件包管理器了。ldd /usr/bin/apt 可用于确认 apt 所需的库是否全部存在。有时可以从救援镜像中的 chroot 环境启动修复,但这通常比重建系统耗时更长。

第三,损坏软件包的列表没有减少。如果您循环运行 dpkg --configure -a 和 apt --fix-broken install 超过一小时,而每次执行都会发现新的软件包,却无法清除上一次发现的问题,说明系统在升级前就已带有升级过程未造成的问题:/usr 下的文件曾被手动修改,软件包被固定或锁定,第三方软件源替换了核心库,或者之前的升级本身从未完成。全新的镜像不存在这些问题,将数据恢复到新系统所需的时间少于逐一查找这些问题。

只有当数据存储在系统之外时,重建才真正省时。这就是快照与备份的区别,也是升级指南要求同时准备二者的原因。

FAQ

中断后可以直接再次运行 do-release-upgrade 吗?

不应将其作为第一步。如果升级程序仍在 screen 会话中运行,请使用 sudo screen -d -r 重新连接;再次运行 do-release-upgrade 会在执行自身的重新连接代码前停止,因为只要有任何软件包等待升级,它就拒绝启动。如果升级程序已退出,请先运行 sudo dpkg --configure -a 和 sudo apt --fix-broken install。如果软件源中已写明 26.04,请使用 sudo apt full-upgrade 完成升级,而不是再次运行升级程序。如果软件源中仍写明 24.04,请运行 sudo apt full-upgrade;如果 /var/run/reboot-required.pkgs 列出 libc6、linux-base 或内核,请重启,然后再次启动升级程序。如果 Prompt=never 在 /etc/update-manager/release-upgrades 中被设置,或者 Ubuntu 的服务器报告“当前无法进行版本升级”,升级程序也会拒绝运行。

为什么升级失败后,do-release-upgrade 提示没有新版本?

因为 base-files(负责写入 /etc/os-release 的软件包)在中断前已经完成升级。该工具现在读取此文件,判断当前系统已是 26.04;在默认的 Prompt=lts 设置下,它找不到可供升级的更新 LTS 版本。如果设置 Prompt=normal,Ubuntu 的升级元数据列出 26.10 后,工具会找到该版本,但随后会因为仍有软件包等待更新而拒绝继续。比较 grep VERSION_ID /etc/os-release 和 grep Suites /etc/apt/sources.list.d/ubuntu.sources,然后使用 sudo apt update && sudo apt full-upgrade 完成升级。

半升级状态的 Ubuntu 服务器可以安全重启吗?

在 sudo dpkg --audit 返回为空之前,不要重启。如果内核已经解包但尚未配置,或 GRUB 尚未重新生成,此时重启是最常见的情况之一:原本 10 分钟可以修复的升级,最终变成需要使用救援镜像处理的任务。完成 dpkg 修复并执行 apt full-upgrade,再运行 update-initramfs -u -k all 和 update-grub,最后才能重启。

如何找出导致升级停止的软件包?

查看 /var/log/dist-upgrade/apt-term.log 的末尾内容,其中保存了 dpkg 的终端输出。日志结束前最后一个出现的软件包,就是当时正在处理的软件包;如果维护者脚本失败,其错误信息会紧接在 dpkg 报错之前输出。/var/log/dpkg.log 是第二个来源:升级停止时记录的时间戳行会列出同一个软件包,但之后通过 dpkg 执行的任何操作也会写入该日志,因此日志末尾可能不再是这个软件包。如果 main.log 以 Python traceback 结束,则表示升级程序自身崩溃,没有软件包出错。

应恢复快照,还是继续修复?

在无法确定失败的软件包、多个软件包卡住、没有控制台访问权限,或服务器必须尽快恢复时,应恢复快照。只有在明确知道唯一故障点,且修复只需执行一条命令时,才应继续修复。恢复前请将 /var/log/dist-upgrade/ 复制到服务器外部,否则第二次尝试仍会以相同方式失败。

这篇文章对您有帮助吗?