Ubuntu 24.04 VPS 升级到 26.04 的安全步骤
自 2026 年 9 月 29 日起,Ubuntu 24.04 服务器可通过 do-release-upgrade 升级到 26.04.1。了解正确升级顺序,以及哪些 VPS 服务可能中断。
何时可以将 Ubuntu 24.04 升级到 26.04?
现在可以在 VPS 上将 Ubuntu 24.04 升级到 26.04。自 29 September 2026 Canonical 为 24.04 LTS 启用升级以来,do-release-upgrade 在 24.04 服务器上会提供 26.04.1。Ubuntu 26.04 LTS(Resolute Raccoon)于 23 April 2026 发布,但 Canonical 只会在第一个点版本发布后开放 LTS 到 LTS 的升级路径,因为该版本会汇总最初几个月发现的安装和升级问题。这一次,等待时间超过了点版本的发布日期:26.04.1 于 27 August 2026 发布,Canonical 又推迟了几周,以等待计划中的 backport 修复近期版本 rust-coreutils 中的回归问题。如果您不熟悉这种版本编号,26.04.1 不是另一个 Ubuntu 版本,而是将四个月修复内容整合到安装介质中的同一个 26.04,这正是 Canonical 首个会提供给现有服务器的版本。
在 29 September 之前,在 24.04 服务器上运行检查会得到以下结果:
sudo do-release-upgradeChecking for a new Ubuntu release
No new release found.这不是服务器故障。如果您现在仍然看到此提示,请检查它所依赖的设置。/etc/update-manager/release-upgrades 在 Ubuntu Server 上包含 Prompt=lts,这表示该工具只会提供下一个长期支持版本,并且只有在 Canonical 开放相应升级路径后才会提供。无论如何都应将其保留为 lts,因为在较新的版本中,normal 还会提供短期支持的过渡版本。在等待期间,Canonical 向不愿等待的用户提供了 do-release-upgrade -d;现在升级路径已经开放,普通命令就是其面向服务器的公告中列出的命令。开始前,请阅读26.04.1 做了哪些更改,以及升级路径何时开放。仍运行 22.04 的服务器无法直接完成这次升级,因为升级工具始终只提供下一个 LTS 版本。因此,通过 24.04 将 22.04 升级到 26.04介绍了第一步升级,以及在第二步升级前应创建的快照。
下面的每条命令都需要您按照给定顺序,在自己的服务器上手动运行。无法在正在升级的计算机上预演版本升级。升级过程会替换 kernel 和 C library,并且需要重启才能完成。
是否应该升级?
Ubuntu 24.04 会持续接收标准安全更新到 2029 年,因此运行正常的生产服务器没有升级期限。升级的理由应是您需要 26.04 提供的内容,例如 PHP 8.5、PostgreSQL 18、MySQL 8.4 LTS、OpenSSH 10.2 或 7.0 内核。“版本号变大了”不是修改一台为客户提供服务的机器的理由。
符合以下任一情况时,不要直接升级现有系统:
- 您从未打开过服务商的控制台(VNC 或串行控制台),也从未通过该控制台登录。如果 SSH 中断,该控制台是重新访问服务器的唯一途径。等到您被锁在服务器外才发现控制台无法使用,就已经太晚了。
- 您无法承受 1 小时的停机,并且没有回滚方案。
- 您的技术栈依赖某个第三方软件源,而该软件源尚未发布
resolute的版本。 - 这台服务器是两年多前手动配置的,目前没人知道其中运行或安装了什么。
通常,更好的方案是新建一台 26.04 VPS,安装您的技术栈并恢复数据,确认新服务器正常响应后再切换 DNS。新服务器验证通过前,您可以让旧服务器继续运行;发生问题时,只需修改 DNS 即可回滚,不必恢复备份。如果选择这种方式,请先阅读新 VPS 的前 10 分钟,并正确配置新服务器。
第 1 步:创建可用于恢复的备份
使用两层备份,因为它们的故障方式不同。服务商快照涵盖整块磁盘,可在几分钟内完成恢复,但创建快照时数据库仍可能正在写入,因此它只能保证崩溃一致性,不能保证应用一致性。使用 restic,将备份存储在服务器之外 进行文件级备份,可以恢复单个文件,并保留一份即使账户被锁定也能使用的副本。
先手动转储数据库。转储是在数据库运行时执行备份的一种方式。
sudo -u postgres pg_dumpall | sudo tee /var/backups/pg-all.sql > /dev/null
sudo mysqldump --all-databases --single-transaction --routines | sudo tee /var/backups/mysql-all.sql > /dev/null
sudo tar czf /var/backups/etc-before-upgrade.tgz -C / etc
sudo chmod 600 /var/backups/pg-all.sql /var/backups/mysql-all.sql--single-transaction 只能为 InnoDB 表生成一致的转储。MyISAM 表需要加锁才能生成一致的转储。/etc tarball 才是你实际会使用的备份,因为其中包含升级过程将要询问你的所有配置文件。
从未执行过恢复的备份,只是一个猜测。现在就从中取出一个文件,避免之后在压力下才需要验证。
第 2 步:先完整更新 24.04
do-release-upgrade 在软件包状态损坏的系统上无法运行,而未完成更新的 24.04 会让后续每个故障都更难判断。
sudo apt update
sudo apt full-upgrade
sudo apt --purge autoremove
sudo dpkg --audit
apt-mark showholddpkg --audit 无输出表示没有软件包处于半配置状态。apt-mark showhold 无输出表示没有软件包被 dpkg hold。它不会显示 APT preference pin;这是另一种机制,同样可能阻止软件包更新,步骤 3 会检查这些设置。对于 showhold 列出的每个项目,使用 sudo apt-mark unhold 和软件包名称解除限制;或者确认该 hold 有其原因,然后停在这里。
如果内核发生变化,请重启,以便从运行其认为当前正在运行的代码的计算机上继续升级。
[ -f /var/run/reboot-required ] && sudo reboot然后检查磁盘空间。升级程序会在安装任何内容前下载完整的新软件包集合。如果空间不足,它会中止,并在消息中指出空间不足的文件系统。
df -h / /boot旧内核通常是原因,sudo apt --purge autoremove 会清理它们。
开始前还要停止一项服务:如果 自动安全更新 在升级过程中启动,它们会占用 dpkg 锁,发行版升级程序会因 Could not get lock /var/lib/dpkg/lock-frontend 停止。先运行 sudo systemctl stop unattended-upgrades,完成后再重新启动 unattended-upgrades 服务。
第 3 步:检查第三方软件源和固定版本的软件包
默认情况下,do-release-upgrade 会注释掉所有非 Ubuntu 软件源,因为为 noble 构建的软件包可能会破坏 resolute 系统。其 --allow-third-party 选项会改为保留这些软件源启用,这正是对应的风险。在工具替你决定之前,先了解自己承担的风险。
ls /etc/apt/sources.list.d/
grep -rhE '^(deb |Types:|URIs:|Suites:)' /etc/apt/sources.list.d/
ubuntu-security-status --thirdparty
ls /etc/apt/preferences.d/Ubuntu 24.04 在该目录中使用两种格式:旧式单行 .list 文件,以及包含 Types: 和 Suites: 字段的 deb822 .sources 文件。默认升级会禁用这两种格式。ubuntu-security-status --thirdparty 列出已安装但没有任何 Ubuntu 软件包存档提供的软件包,这准确反映了你额外安装的软件包数量。只有当 /etc/apt/preferences.d/ 中的文件名没有扩展名,或以 .pref 结尾,并且文件内容只包含字母、数字、连字符、下划线和句点时,APT 才会将其作为固定规则读取;其他文件会被 APT 忽略,通常还会显示提示信息。指定 noble 的固定规则可能会在升级后让软件包保持旧版本,具体取决于仍可用的版本以及固定规则设置的优先级。因此,请逐个读取这些文件,并判断它们是否仍然需要保留。
对于每个第三方软件源,请先确认供应商已针对新的代号发布软件包。Docker 的套件列表位于 https://download.docker.com/linux/ubuntu/dists/,其他供应商也提供相同的目录。指向不存在套件的软件源会在升级后的首次 apt update 中产生以下错误:
E: The repository 'https://download.docker.com/linux/ubuntu resolute Release' does not have a Release file.Docker 现在发布了 resolute 套件。在供应商发布该套件之前,请保持所有缺失套件的软件源禁用。将代号改成供应商确实构建过的其他代号,会导致安装链接到错误系统库的软件包。
第 4 步:在 tmux 中运行升级,不要使用普通的 SSH shell
服务器升级程序通常在 GNU screen 中运行,并支持在连接断开后重新连接,因此 SSH 断开本身不会终止升级。也请在您自己的 tmux 会话中运行它,这样您就有一个可按名称重新连接的会话。
sudo apt install -y tmux
tmux new -s upgrade在该会话中:
sudo ufw allow 1022/tcp
sudo do-release-upgrade升级程序会在进行任何更改前,在端口 1022 上启动第二个 SSH daemon,并显示提示:
To make recovery in case of failure easier, an additional sshd will be started on port '1022'. If anything goes wrong with the running ssh you can still connect to the additional one.它不会为该端口配置防火墙规则,因为未经询问就在防火墙中开通端口可能造成意外风险。请在开始前自行开放 1022,完成 sudo ufw delete allow 1022/tcp 后关闭该端口。请注意,您的服务提供商可能还会在其控制面板中运行第二层防火墙,该防火墙位于服务器之外。
如果连接仍然断开,请重新登录并运行 tmux attach -t upgrade。您离开期间,升级仍会继续运行。如果升级没有继续,而您重新连接后发现 dpkg 处于半配置状态,或 apt 源一部分属于 noble、另一部分属于 resolute,请参阅恢复失败的版本升级,其中介绍了如何修复软件包状态,以及何时应停止修复并改为恢复快照。
第 5 步:谨慎回答配置文件提示
dpkg 只会提示您处理由您或脚本修改过的文件。因此,每个提示对应的都是由您或脚本修改过的文件;按 Enter 默认会保留当前版本。
Configuration file '/etc/ssh/sshd_config'
==> Modified (by you or by a script) since installation.
==> Package distributor has shipped an updated version.
What would you like to do about it ? Your options are:
Y or I : install the package maintainer's version
N or O : keep your currently-installed version
D : show the differences between the versions
Z : start a shell to examine the situation
The default action is to keep your current version.
*** sshd_config (Y/I/N/O/D/Z) [default=N] ?每次都先按 D。先查看具体更改,再使用 N 保留您的版本,或安装维护者提供的版本。默认选项已经是 N,但对每个软件包来说,保留旧文件都不一定安全:某些配置更改是升级后的系统正常运行所必需的。
保留您的文件需要承担相应代价:您不会获得新的默认配置。待系统恢复运行且没有时间压力后,再进行配置合并。
sudo find /etc -name '*.dpkg-dist' -o -name '*.dpkg-new'每个列出的文件都是维护者提供的版本,保存在您的文件旁边。逐个比较差异,并将重要设置复制过来。以下两个文件需要格外谨慎:/etc/ssh/sshd_config,因为选择错误会结束您的会话;以及 Web 服务器配置,因为选择错误会导致网站停止服务。
从 Ubuntu 24.04 开始,needrestart 默认会自动重启受影响的服务。如果您恢复了交互模式,请接受完整列表。仍在使用旧共享库的守护进程,在重启前仍会暴露于更新已修复的漏洞。
第 6 步:重启,然后检查计算机
sudo reboot系统恢复运行后:
lsb_release -a
uname -r
systemctl --failed
journalctl -p err -b --no-pager | head -50
sudo apt update && sudo apt full-upgrade
sudo apt --purge autoremovelsb_release -a 应报告 Release: 26.04 和 Codename: resolute。uname -r 应显示 7.0 内核。systemctl --failed 应列出 0 个单元;如果列出了任何单元,请优先处理这些问题。最后运行 apt update 刷新软件包索引,然后运行 apt full-upgrade 安装升级获取软件包后发布的更新。
PostgreSQL 16 到 18:悄悄滞后的集群
Ubuntu 24.04 随附 PostgreSQL 16,Ubuntu 26.04 随附 PostgreSQL 18。升级会将 18 安装到 16 旁边,但不会迁移数据。Debian 的 postgresql-common 层仅在服务器软件包安装时系统中尚不存在任何集群的情况下创建主集群,因此,已有的 PostgreSQL 16 集群不会自动为 18 创建一个监听 5433 端口的空集群。应用会继续连接 5432,一切看起来都正常,这就是为什么人们往往几个月后才发现这个问题。
pg_lsclusters版本 16 的条目表示该集群仍在使用 16。如果 pg_lsclusters 还列出了一个 18 main 集群,请在使用 sudo pg_dropcluster --stop 18 main 删除它之前确认该集群为空,因为 pg_upgradecluster 不会写入已经存在的目标集群。请在可以停止应用时执行迁移:
sudo pg_upgradecluster 16 main
pg_lsclusters
sudo -u postgres vacuumdb --all --analyze-only默认方法会导出 16 中的数据,再将其重新加载到 18,因此需要预留大约等于数据库大小的磁盘空间。-m upgrade 改用 pg_upgrade,在大型数据库上速度快得多。完成后,查看 Port 列:新集群会接管 5432,旧集群则保持停止状态。软件包提供的升级钩子会自动执行 analyze 操作;上面的命令会再次显式执行该操作。
让应用使用新集群运行几天并进行测试。确认无误后,再删除旧集群:
sudo pg_dropcluster 16 main
sudo apt purge postgresql-16旧集群的数据目录是你最快的回滚手段。不要在升级当天删除它。
MySQL 8.0 到 8.4:导致服务器停止的已移除选项
26.04 会将 MySQL 从 8.0 升级到 8.4 LTS,其中有两项变更会导致服务器出现问题。
首先,如果配置中包含新版本已移除的选项,mysqld 将拒绝启动。default_authentication_plugin 是最常见的选项,因为许多旧版指南都要求设置它。服务会启动失败,而 journalctl -u mysql -n 50 会直接指出未知变量。从 /etc/mysql/mysql.conf.d/ 下的文件中删除该行,然后执行 sudo systemctl start mysql。
其次,mysql_native_password 插件在 8.4 中不再默认启用,因此仍在使用该插件的账户完全无法登录。趁仍在使用 8.0 时检查:
sudo mysql -e "SELECT user, host, plugin FROM mysql.user;"在升级前迁移所有显示为 mysql_native_password 的账户,然后在应用配置中更新密码:
ALTER USER 'appuser'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'a new password';如果客户端库过旧,无法使用 caching_sha2_password,可以在 8.4 中通过在 [mysqld] 下添加 mysql_native_password=ON 来重新启用旧插件。应将此作为临时过渡方案,并设定终止日期,因为 MySQL 已在 9.0 中移除该插件。
PHP 8.3 升级到 8.5:您的 vhost 仍指向已不存在的套接字
24.04 提供 PHP 8.3,26.04 提供 PHP 8.5。软件包会安装到带版本号的路径中,且不会改写 Web 服务器配置。包含 fastcgi_pass unix:/run/php/php8.3-fpm.sock; 的 nginx vhost 现在指向一个没有进程创建的套接字,因此每个 PHP 请求都会返回 502,nginx 错误日志会显示:
connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory)将其指向新的套接字,测试配置,然后重新加载:
sudo sed -i 's/php8.3-fpm.sock/php8.5-fpm.sock/' /etc/nginx/sites-available/example.com
sudo nginx -t
sudo systemctl reload nginx在使用 mod_php 的 Apache 上,症状有所不同:Apache 根本无法启动,sudo apache2ctl -t 报告无法加载 libphp8.3.so,因为该文件不存在。已启用的模块是指向已被删除软件包的符号链接。
sudo a2dismod php8.3
sudo a2enmod php8.5
sudo systemctl restart apache2如果您按照在 Ubuntu 24.04 上搭建 LAMP 堆栈配置了服务器,那么这两处路径都应检查,因为该指南会留下带版本号的模块名称和套接字。
您的 php.ini 调优设置也不会自动迁移。memory_limit、upload_max_filesize 以及您设置的其他内容都位于 /etc/php/8.3/ 中,而新的目录树会从默认值开始。比较这两个文件,然后手动复制配置值。将整个旧文件覆盖到新文件上,会把 8.3 的默认值带入 8.5 安装。随后运行 php -m 并进行比较:作为 php8.3-redis 安装的扩展需要其对应的 php8.5- 软件包;如果该扩展来自 PPA,升级程序会禁用该软件源,扩展也就会直接缺失。
证书还需要单独检查一次。升级后运行 sudo certbot renew --dry-run --run-deploy-hooks。它会执行完整的续期流程,包括 Web 服务器重新加载钩子,但不会修改当前使用的证书。如果钩子调用的服务名称或二进制文件已经变更,此处就会直接失败,而不是等到下次续期时静默失败。在 nginx 上使用 Let's Encrypt 配置 Certbot介绍了这些钩子应采用的形式。
SSH:导致当前会话终止的故障
sshd_config提示符是最容易把自己锁在服务器外的地方。回答 Y 会安装维护者提供的文件,并丢弃你的 PermitRootLogin、PasswordAuthentication、AllowUsers、Port 以及你添加的所有其他行。如果防火墙只允许自定义端口,而软件包中的配置监听 22,那么下一次连接会被拒绝;你当前所在的会话也会成为你最后一个可用会话。
请在升级前阻止这种情况发生。24.04 中的 /etc/ssh/sshd_config 以 Include /etc/ssh/sshd_config.d/*.conf 开始。对于大多数设置,OpenSSH 保留它读取到的第一个值,因此,顶部包含的 drop-in 文件会覆盖后面相同的设置。有少数关键字例外:Port 和 ListenAddress 接受多个值,因此 drop-in 文件中的 Port 行会添加一个端口,而不是替换下面已设置的端口。请将设置移到 dpkg 不管理的文件中:
sudo tee /etc/ssh/sshd_config.d/99-local.conf > /dev/null <<'EOF'
PermitRootLogin no
PasswordAuthentication no
AllowUsers deploy
EOF
sudo chmod 644 /etc/ssh/sshd_config.d/99-local.conf
sudo sshd -t && sudo systemctl restart ssh当 /etc/ssh/sshd_config 中不再包含你的设置时,该提示符就不再重要:无论选择哪个回答,你的设置都会保留,因为它们位于其他文件中。
自定义端口还需要进行一项检查,因为它可能并不在你以为的位置:
systemctl is-enabled ssh.socket如果该命令输出 enabled,则监听端口由 systemd 打开,而不是由 sshd 打开。自 22.10 起,Ubuntu 一直对 sshd 使用 socket activation。在 24.04 中,systemd generator 会从 sshd 配置中读取 Port 和 ListenAddress 设置,并将其转换为 socket 的监听地址,但只有在 systemd 重新加载单元后才会执行。正因如此,修改 Port 2222 后看起来没有效果:它会在 sudo systemctl daemon-reload && sudo systemctl restart ssh.socket 后生效,而软件包提供的 sshd_config 现在也带有说明这一点的注释。若要直接在 socket 单元中设置端口,请使用 sudo systemctl edit ssh.socket:
[Socket]
ListenStream=
ListenStream=2222空的 ListenStream= 是必需的。它会清除继承的值;如果没有它,该 socket 会同时监听 22 和 2222。使用 sudo systemctl daemon-reload && sudo systemctl restart ssh.socket 应用设置。
升级后,在关闭当前会话之前:
sudo sshd -t
sudo systemctl status ssh.socket --no-pager
sudo ss -lntp | grep -E ':(22|2222)'然后在自己的计算机上打开第二个终端,再次登录。第二个终端中的可用 shell 是唯一有效的验证方式。在确认第二个会话可用之前,请保持第一个会话打开。VPS 上的 SSH 加固介绍了该 drop-in 文件中值得保留的设置。
如果已经来不及,服务商的 Web 控制台可以提供不使用 SSH 的登录方式。在那里登录并修复配置,然后运行 sudo sshd -t,再重启服务。正因如此,应在升级前测试控制台访问,而不是等到升级过程中再测试。
FAQ
为什么在 Ubuntu 24.04 上运行 do-release-upgrade 时显示“No new release found”?
自 29 September 2026 起不应再出现此提示,因为 Canonical 在当天启用了从 24.04 LTS 升级到 26.04.1 的路径。在此之前出现该提示是正常的:Ubuntu 26.04 LTS 于 23 April 2026 发布,26.04.1 于 27 August 发布;Canonical 为回移植 rust-coreutils 回归问题的修复,又暂时关闭了该升级路径数周。如果仍然看到此提示,请检查 /etc/update-manager/release-upgrades 是否包含 Prompt=lts。这是 Ubuntu Server 的默认设置,仅提供下一个长期支持版本。请将其保留为 lts。
升级完成后必须重启服务器吗?
是。升级会安装新内核、新 C 库和新的 init 系统。运行中的系统在重启前仍会使用旧版本。do-release-upgrade 会在结束时要求重启。如果机器一直运行到“稍后”,系统就会同时使用两个版本中的组件。机器恢复后,检查 uname -r 中的内核版本,并检查 systemctl --failed 以确认哪些服务未能恢复。
应该原地升级,还是新建一台 26.04 服务器?
条件允许时,建议新建服务器。新的 VPS 可以在旧服务器继续提供网络流量期间安装软件栈、恢复数据并完成测试。这样回滚只需修改 DNS,而不必从备份恢复。以下情况可以原地升级:服务器保存的状态难以迁移;服务商按机器计费;或者你已有快照并确认可以通过控制台访问。原地升级路径已经比较成熟,但升级运行期间无法轻易回退。
如果升级期间 SSH 连接断开,会发生什么?
服务器升级程序通常使用 GNU screen,因此 SSH 连接断开本身不会终止升级。如果你是在上文命名的 tmux 会话中启动升级,重新连接后运行 tmux attach -t upgrade 即可继续。升级程序还会在 1022 端口启动备用 SSH daemon,作为另一种连接方式。但它不会为该端口开放防火墙,因此请先自行允许 1022,完成后再关闭该端口。
升级后我的 PHP 站点返回 502。哪里出问题了?
PHP FPM 套接字路径随版本发生了变化。Ubuntu 24.04 使用 PHP 8.3,26.04 使用 PHP 8.5,因此 /run/php/php8.3-fpm.sock 已不存在,但你的 nginx vhost 仍引用该路径。nginx 错误日志会显示 connect() to unix:/run/php/php8.3-fpm.sock failed (2: No such file or directory)。将 fastcgi_pass 更新为 8.5 的套接字路径,运行 sudo nginx -t,然后重新加载 nginx。对于使用 mod_php 的 Apache,对应的修复是运行 sudo a2dismod php8.3,再运行 sudo a2enmod php8.5 并重启服务。