报告 Installed: (none) 的 VPN 软件包并没有缺失,它只是没有安装。决定你能否安装它的是 Candidate 行,APT 由索引、套件名、架构以及任何生效的固定规则推导出该行。大多数“VPN 软件包消失”的报告,最终都是候选问题,而不是打包问题。在改动任何一条源条目之前,先把两行都读完。

我先检查候选,因为这只花一条命令,就能排除一半常见猜测。

policy 的输出到底告诉你什么

apt-cache policy 读取的是本地软件包缓存,而不是网络。它会打印已安装版本、候选版本,以及每个提供该软件包的索引及其附带优先级。

apt-cache policy openvpn
apt-cache madison openvpn
apt list -a network-manager-openvpn

候选是 APT 此刻会选择的版本。madison 列出每个源提供什么以及对应优先级,你就是这样发现某个包虽然存在于索引中,却输掉了固定竞争的。apt-cache 手册把两者都记录为缓存读取,所以二者都不能证明镜像此刻可达。

如果候选行为空或显示 (none),那么按当前配置,已配置的源中没有任何东西适用于这个系统。

候选消失的四个原因

实践中原因几乎总是以下四种之一,而且每种都有不同的修法。

源里的套件名必须与软件包构建时对应的发行版一致。把 Debian bookworm 系统指向 trixie 镜像,或在升级期间让某个 Ubuntu 版本在 sources.list.d 文件里被改名,对只存在于另一套件中的软件包毫无帮助。把 lsb_release -cs 与每条条目的套件字段对照一下。

APT 只看得到为 dpkg 已知架构构建的软件包。32 位容器、arm64 镜像,或要求只针对 amd64 发布的软件包的树莓派安装,得到的是空候选,而不是错误提示。dpkg --print-architecture 和 dpkg --print-foreign-architectures 会告诉你实际处在哪个集合里。

组件同样重要。当只启用了 main 时,contrib 或 non-free 里的软件包是不可见的,Ubuntu 的 universe 也是如此。索引存在,包里也有它,只是你启用的组件列表没有把它算进去。

固定是最安静的那个原因。/etc/apt/preferences.d 里的文件可以把某个包压到安装阈值以下,于是完全合格的候选从输出里消失,而索引仍然列着它。由于 policy 会在每个源旁边打印优先级,凡是每个源的固定编号都很低的包,就是线索。

过期的索引看起来像缺失的软件包

缓存是一份快照。如果上一次 apt update 在某个索引上失败,查询仍会从旧副本作答,你期待的软件包可能并不在那份副本里。

apt update 会按索引打印错误,所以去读它们,而不是直接滚到最后一行。

因签名错误、过期的 release 文件或不可达镜像而失败的刷新,会把上一个索引留在原处。这是合理的设计,因为镜像短暂不可用时它保住了可用的缓存。副作用是:仓库离线时搜索仍可能成功。这也意味着,在你弄清索引上次是什么时候取回的之前,某个包不存在说明不了任何问题。在责怪软件包名字之前,先看看 /var/lib/apt/lists 下文件的日期。

说出你真正需要的软件包

OpenVPN 是守护进程,人们通常想要的那几块是单独的软件包。

引擎、NetworkManager 插件和桌面编辑器是三个名字不同的软件包,而插件还有一个在发行版之间名字不同的 GTK 版本。apt-cache search --names-only openvpn 匹配的是名称和提供的名称,而不是描述;当你大致知道那东西叫什么时,要的就是这个。

如果名字确实陌生,先在描述里搜一次,然后再回到精确名称。不要加上从别的发行版借来的 -gui 后缀,就断定软件包不再存在。

最后再改源,然后验证这次事务

添加仓库会改变由谁提供你的更新,所以它属于调查的结尾,而不是开头。

在此之前,确认发行版、架构、组件和固定状态。写下你查过这四项中的哪些,免得下一个人再扫一遍。如果四项都对而候选仍然缺失,诚实的结论是这个发行版不提供那个软件包。剩下的选择是 backport、厂商软件包或另一个受支持的发行版,每一种都是有意的选择,而不是猜测。

当候选真的出现时,先模拟再提交:带软件包名的 apt-get install --simulate 会显示将拉入什么、移除什么。软件包可用、安装完成和隧道可用仍是三个独立阶段,隧道在承载流量之前还需要它的配置、凭据、路由和 DNS。

相关文章