看到这个报错组合,我第一反应是:这不是阿里云的锅,多半是源列表、GPG 公钥和系统版本三者之间有一处或多处错位。sudo apt-get update 提示没有数字签名,紧接着安装 foremost 又提示无法定位软件包,这类问题在 Debian/Ubuntu 系甚至 Kali 上都非常典型。很多人一着急就不断换源,从官方源换成阿里云,再从阿里云换成清华源,结果问题原地打转。
这篇就顺着这条报错链条,把“为什么没签名”“为什么定位不到包”“换源为什么没用”一次讲透,并给出一套可以直接复制的修复流程。不管你是刚入门的 Linux 新手,还是被这个问题卡了几个小时的老哥,按顺序操作基本都能收尾。
1. 先理清报错链条:没有数字签名和无法定位软件包其实是同一件事
1.1 apt 更新时的签名校验是怎么工作的
apt-get update 做的事情并不是“把软件下载下来”,而是从 /etc/apt/sources.list 和 /etc/apt/sources.list.d/ 里配置的软件源下载“软件包索引”。这个索引里记录了每个软件包的名字、版本、依赖关系、下载地址。apt 后续执行 apt-get install 时,是在本地索引里搜索匹配的包,再根据索引给出的地址去下载真正的 .deb 文件。
问题就出在这个“索引”上。为了安全,apt 要求索引文件必须经过 GPG 签名验证。正常情况下,发行版官方会对每个版本的 InRelease 或 Release.gpg 文件做数字签名,apt 用系统里预先安装好的公钥去验证这个签名。验证通过,索引才会被接受;验证失败,apt 会拒绝使用这个源,并在 update 阶段报出类似下面的错误。
code复制W: GPG error: http://mirrors.aliyun.com/ubuntu jammy InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 3B4FE6ACC0B21F32
E: The repository 'http://mirrors.aliyun.com/ubuntu jammy InRelease' is not signed.
看到 NO_PUBKEY 或 is not signed,说明系统里没有对应的公钥,或者公钥已经过期、被吊销。旧版 Kali 上还会出现一种比较迷惑的提示:“没有数字签名”。意思是一样的:apt 无法验证这个源的身份,于是选择不信任,拒绝使用。
1.2 为什么索引没更新成功,foremost 就“无法定位”了
很多人的操作顺序是这样的:先跑 sudo apt-get update,看到签名错误;然后不管不顾直接 sudo apt-get install foremost,结果出现 E: Unable to locate package foremost。这两条报错之间,其实是因果关系。
因为 update 失败,apt 本地根本没有可靠的最新索引,甚至可能连旧的索引都被清理掉了。install 阶段在空索引里搜索 foremost,自然什么都搜不到。换句话说,你看到的“无法定位软件包”只是表面症状,根子还在“没有数字签名”这一步。修复的重点不是去执着于 foremost 这个包本身,而是先把 apt-get update 跑通。
这里也顺带说一句:foremost 是数据恢复和取证领域很常用的一个工具,它按照文件头特征去扫描磁盘镜像或存储设备,恢复被删除的文件。Kali 里通常预装,Ubuntu/Debian 则一般需要手动安装。在 Ubuntu 上它位于 universe 组件里,Debian 上位于 main 组件里。如果源配置里没启用对应组件,能搜到包名但装不上,或者干脆提示“无法定位”。这一点后面排查时还会用到。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动手排查前,先把这三项基础信息确认清楚
2.1 确认发行版版本与代号
修复源问题,第一步不是改源,而是搞清楚自己系统到底什么版本。不同版本对应不同的源地址和版本代号,写错了自然报错。执行下面两条命令中的任意一条。
bash复制lsb_release -a
cat /etc/os-release
比如 Ubuntu 22.04 会显示 jammy,Debian 12 会显示 bookworm,Kali 则显示 kali-rolling。把代号记下来,后面写源列表要用。很多人就是在这里搞混:明明装的是 Ubuntu 20.04(代号 focal),源列表里却写了 jammy;或者拿 Debian 的源直接填进 Ubuntu,结果 apt 更新时把仓库内容解析得乱七八糟。
还要注意:Ubuntu 的版本代号对应 dists/ 目录下的子目录名,Debian 的也一样。源的 URL 路径里必须包含正确的代号,镜像站才能在服务器上找到对应的索引目录。写错一个单词,服务器直接返回 404,apt 就会提示 Failed to fetch,或者是某个仓库“没有数字签名”。
2.2 翻一翻当前的源列表到底长什么样
查看当前源列表,重点看有没有历史遗留的多余配置。
bash复制cat /etc/apt/sources.list
ls -l /etc/apt/sources.list.d/
cat /etc/apt/sources.list.d/*.list 2>/dev/null
常见的情况是:系统里同时存在官方源、阿里云源、某个第三方源,甚至有人曾在 /etc/apt/sources.list.d/ 下手动添加过已经不维护的仓库。APT 会合并所有这些源,只要有一个源签名失败,update 就会报错。操作上我一般建议先把 sources.list.d/ 里的第三方源全部临时禁用(把 .list 后缀改成 .bak),只保留主源,排错更干净。
另外,有的版本用的是 .sources 格式(Debian 12 之后的默认格式),内容结构略有不同。如果是这种格式,直接编辑 /etc/apt/sources.list 或 /etc/apt/sources.list.d/debian.sources 也可以,但要注意语法是 Types: deb、URIs: 这种写法,和传统的单行 deb 写法不一样。
2.3 验证网络和镜像站是否真的可用
如果系统本身网络异常,或者镜像站在你所在网络环境下不可达,也会出现各种诡异报错。先做两个简单测试。
bash复制ping -c 4 mirrors.aliyun.com
curl -I http://mirrors.aliyun.com/ubuntu/dists/jammy/InRelease
curl 命令能看到 HTTP 状态码。正常情况返回 200 OK,说明镜像站可用。如果返回 404 Not Found,说明这个镜像站上根本没有 Ubuntu jammy 的目录,这时候换源是没用的,问题在于你指定的版本不对,或者这个镜像站已经下架了旧版本。
还有一种比较少见但真实存在的情况:系统时间不准,偏差太大导致 GPG 签名有效期校验失败。这种报错一般不是 NO_PUBKEY,而是提示签名过期(Signature expired)或者“无法验证”。在虚拟机和长期休眠的机器上,时间漂移很常见。可以先执行 date 看一眼系统时间,再用下面命令校准。
bash复制sudo timedatectl set-ntp true
如果 NTP 服务不好使,可以临时手动校准,确认时间正常后再重新 update。
3. 对症下药:三类典型故障的成因与解法
3.1 场景A:系统版本太老,官方源已经停止维护
这是“没有数字签名”报错里最常见的一种,特别是老鸟手里那台很多年没升级的 Ubuntu、Debian 或早期 Kali。发行版生命周期结束后,官方会把旧版本源挪到归档地址,国内镜像站通常也会清理旧版本的目录。这时候你继续请求旧版本的 InRelease 文件,镜像站要么返回 404,要么给出一个已失效的签名文件,apt 自然报错。
Ubuntu 的归档地址是 http://old-releases.ubuntu.com/ubuntu/,Debian 是 http://archive.debian.org/debian/。如果你确认系统版本确实很老,且不打算升级系统,可以把源替换成归档地址试试。比如 Ubuntu 18.04(bionic)已经结束标准支持,用官方归档源的方式类似下面这样。
code复制deb http://old-releases.ubuntu.com/ubuntu/ bionic main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu/ bionic-updates main restricted universe multiverse
deb http://old-releases.ubuntu.com/ubuntu/ bionic-security main restricted universe multiverse
不过要提醒一句:归档源通常速度一般,而且很多国内网络环境访问不太稳定。如果这台机器不是必须守着旧系统,我更推荐直接升级到受支持的版本,或者干脆重新装新版系统。对一个数据恢复工具的需求来说,重装系统的成本往往比折腾一个停止维护的系统更低。
Kali 的情况有点特殊。它没有 LTS 版本,采用滚动发布模式,官方推荐始终使用 kali-rolling 源。如果你用的是很多年前的 Kali ISO,源列表里写的还是 sana、kali-2017 这类旧代号,那必然报错。解决办法就是把源改成 kali-rolling。
3.2 场景B:公钥缺失或密钥过期导致的 NO_PUBKEY
如果你看到的是类似 NO_PUBKEY 的错误,说明系统缺少对应源的公钥。原因通常是有人手动添加了一个第三方 PPA 或第三方仓库,但没有导入该仓库的签名公钥。
传统做法是用 apt-key 导入。比如报错里提示缺少 3B4FE6ACC0B21F32 这个公钥,执行:
bash复制sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
不过这里有两个坑。第一,apt-key 在新版 Debian/Ubuntu 中已经被标记为弃用,部分新系统上命令可能不可用;第二,如果在公钥服务器上找不到对应密钥,这个命令会超时或报错。遇到这种情况,更可靠的方式是去该源的官网找到官方发布的公钥文件,用 gpg 导入。
bash复制wget -qO - https://example.com/keys/repo.asc | sudo gpg --dearmor -o /usr/share/keyrings/example-archive-keyring.gpg
然后在源列表里通过 signed-by 参数指定这个 keyring 文件。
code复制deb [signed-by=/usr/share/keyrings/example-archive-keyring.gpg] https://example.com/apt/ stable main
但我想强调一下:如果你只是使用阿里云、清华、中科大这些公开镜像,根本不需要额外导入什么公钥。官方源的公钥都会随系统安装包预装,或者通过 ubuntu-keyring、debian-archive-keyring 这类包提供。在阿里云源上报 NO_PUBKEY,绝大多数情况不是真的缺少密钥,而是源列表本身写错了,导致 apt 把阿里云源里的内容当成了另一个来源的仓库来验证。所以遇到 NO_PUBKEY,先检查源列表格式,再考虑密钥问题。
3.3 场景C:源列表写错格式,镜像路径根本没有对应版本
这是不少新手最容易忽略的。阿里云镜像站对不同发行版有不同的路径,写的时候必须一一对应。
- Ubuntu:
https://mirrors.aliyun.com/ubuntu/ - Debian:
https://mirrors.aliyun.com/debian/ - Debian Security:
https://mirrors.aliyun.com/debian-security/ - Kali:
https://mirrors.aliyun.com/kali/
一个很典型的错误是把 Kali 的源写成 https://mirrors.aliyun.com/ubuntu/,或者把 Ubuntu 的源写成 https://mirrors.aliyun.com/centos/。镜像站上根本没有对应路径,或者路径下没有适合你系统版本的索引,签名自然无法通过。还有人在 deb 行结尾漏掉了 main、universe 这些组件名称,apt 同样无法正确解析索引。
另外再提一个细节:Debian 源里的 security 仓库,早期很多人会写 https://mirrors.aliyun.com/debian-security/,这是对的;但也有教程让人写成 http://security.debian.org/。如果系统本身网络环境访问国外源慢,建议统一都走阿里云镜像的 debian-security 路径,避免因为超时导致签名文件拉取不完整。
4. 手把手操作:换源、修密钥、安装 foremost 的完整流程
4.1 第一步:备份源列表并写入经过验证的新源
先备份,再动手。备份的重要性我强调过很多次,改坏源列表后能一条命令退回去,比什么都强。
bash复制sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
然后清空源列表并写入新内容。这里建议用 nano 或 vim 直接编辑,别用一个 sed 命令图省事。源列表这种文件,一次性写对比反复调试更重要。下面按 Ubuntu 22.04、Debian 12、Kali 各给一份常用模板。
Ubuntu 22.04(代号 jammy)使用阿里云:
code复制deb https://mirrors.aliyun.com/ubuntu/ jammy main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ jammy-updates main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ jammy-backports main restricted universe multiverse
deb https://mirrors.aliyun.com/ubuntu/ jammy-security main restricted universe multiverse
Debian 12(代号 bookworm)使用阿里云:
code复制deb https://mirrors.aliyun.com/debian/ bookworm main contrib non-free non-free-firmware
deb https://mirrors.aliyun.com/debian/ bookworm-updates main contrib non-free non-free-firmware
deb https://mirrors.aliyun.com/debian-security/ bookworm-security main contrib non-free non-free-firmware
Kali 滚动版使用阿里云:
code复制deb https://mirrors.aliyun.com/kali/ kali-rolling main non-free contrib
注意,如果你不是这些版本,把对应代号换成你自己的版本代号即可。Ubuntu 的代号可以看 /etc/os-release 里的 VERSION_CODENAME,Debian 同理。不要凭感觉写。
4.2 第二步:导入缺失公钥
写完源列表后,先执行一次 sudo apt-get update。这次仍然可能报错,但报错信息会比之前更明确。如果提示 NO_PUBKEY,先按 3.2 里的方式处理。
不过针对阿里云源,还有一个更常见的“假签名问题”:某些旧版系统因为 keyring 包太旧,不识别新的签名算法或签名方式。这时候先升级 keyring 包试试。
bash复制sudo apt-get install --reinstall ubuntu-keyring
Debian 系统则对应:
bash复制sudo apt-get install --reinstall debian-archive-keyring
如果系统连这些包都因为源问题装不上,那就先临时改回一个能用的官方源,更新一次 keyring 之后再换回国内源。这个顺序大多数人没意识到,其实很关键。
4.3 第三步:更新索引并安装 foremost
确认 apt-get update 无报错后,再查看软件包是否已经在索引里。
bash复制apt-cache search foremost
如果输出里有 foremost,直接安装:
bash复制sudo apt-get install foremost -y
安装完成后验证一下:
bash复制foremost -V
如果能输出版本信息,说明安装成功。这里我特别说一下:apt-get update 和 apt-get install 是两个独立步骤,有些人只执行了 apt-get update 就去 install,其实没问题;但更多人是在 update 还报错的情况下强行 install,那必然失败。务必先保证 update 的返回状态是正常的。
5. 换了阿里云源依然失败的 6 个排查方向
5.1 镜像站没有同步该版本,先查 dists 目录
换阿里云源之后还报“无法定位软件包”或签名错误,一个隐蔽原因是:阿里云镜像站可能因为存储策略,没有同步某个特定版本的目录。你可以直接用浏览器或 curl 打开镜像站的 dists 目录,检查里面有没有你的版本代号。
bash复制curl -s https://mirrors.aliyun.com/ubuntu/dists/ | grep -oE 'jammy|focal|bionic|bookworm|bullseye'
如果没有找到对应代号,说明镜像站当前不提供这个版本的同步。这种情况换阿里云没用,需要换一个仍然保留该版本的镜像源。比较稳定的是清华 tuna、中科大 ustc 和华为云镜像。比如清华源路径 https://mirrors.tuna.tsinghua.edu.cn/ubuntu/,中科大源路径 https://mirrors.ustc.edu.cn/ubuntu/。把源列表里的 mirrors.aliyun.com 替换成上述域名即可。我实测过,不同镜像站对旧版本的保留策略确实不一样,这个方案比死磕阿里云靠谱。
5.2 组件没开全、架构不对、本地缓存太老的坑
就算版本代号正确,如果源列表里缺少 universe 或 multiverse 组件,很多软件包也会搜不到。前文提过,Ubuntu 的 foremost 在 universe 仓库里。所以你的源列表末尾一定要带上完整的组件名:
code复制main restricted universe multiverse
再来看另一个坑:系统架构。如果你的设备是树莓派或其他 ARM 设备,使用的架构是 arm64,但下载源写的是 amd64 的专用源(某些第三方源会区分架构),也会出现“找不到包”的情况。用下面的命令确认当前架构。
bash复制dpkg --print-architecture
正常源列表里的 deb 行是不需要写架构的,apt 会按当前系统架构自动拉取对应目录。但如果之前有人手动配置过 [arch=amd64] 这种限定标志,就需要把架构和你实际的系统架构对齐。
还有一种很坑的情况是本地 apt 索引缓存损坏,导致 update 后仍使用旧数据。遇到多次改源后依旧定位不到包,可以清理缓存后重试。
bash复制sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo apt-get update
/var/lib/apt/lists/ 是本地缓存的包索引目录,删掉后 apt 会强制重新下载所有源索引。这个操作是安全的,只是下次更新会稍慢一点。
5.3 兜底方案:源码编译安装 foremost
如果因为各种原因,apt 源始终修不好,或者你不想在这个问题上继续耗时间,可以直接从源码编译安装 foremost。这个方案不依赖 apt 源是否有这个包,只要有编译环境和网络能访问 GitHub。
bash复制sudo apt-get install -y gcc make libextractor-dev
git clone https://github.com/korczis/foremost.git
cd foremost
make
sudo make install
编译完成后执行 foremost -h 看帮助信息。这种方式绕开了 apt 的索引和签名机制,直接安装到系统里。代价是以后卸载、升级都要手动处理,而且依赖关系不会自动管理。如果系统连 gcc、make 都装不上,那就只能先把 apt 源修好,装上基础编译工具后再走这条路。对大多数情况,我仍然建议优先把 apt 源修好,因为后续系统更新、装其他软件都会受益。
最后再分享一个容易混淆的点。这次的问题发生在 Ubuntu/Debian 系里,“没有数字签名”指的是 apt 索引的 GPG 签名。而 Windows 系统上经常出现的“Windows 无法验证此设备所需驱动程序的数字签名”,说的是驱动文件的签名证书问题,两者完全是两套机制。如果你是在虚拟机里装 Win7 后 VMware Tools 装不上、报数字签名错误,那不是改 apt 源能解决的,正确方向是更新虚拟机证书或临时禁用驱动强制签名。不要把两套问题的排查思路混在一起,否则越查越乱。
根据我自己的经验,这类源问题九成以上是版本代号写错、组件没写全、或者公钥没导入这三类原因造成的。操作前先备份源列表,确认版本代号,再动源文件,一次性过掉的概率非常高。别急着把所有国内源都试一遍,把原理搞清楚,一次就能解决。
