广告位 · 页头(后台-模块管理-新建模块后替换此区域)

Ubuntu更新时提示GPG error签名错误怎么修复?

在 Ubuntu 或 Debian 系发行版上执行 sudo apt update 时,偶尔会看到类似 The following signatures couldn't be verified because the public key is not available 的提示,后面通常跟着 NO_PUBKEY 和一串十六进制密钥 ID。有些用户还会遇到 EXPKEYSIG 或 KEYEXPIRED 报错。出现这类 GPG error 并不代表系统已经损坏,而是 APT 在验证软件源元数据时,没法找到与签名对应的公钥,或者找到的密钥已经过期。换句话说,这是软件源的可信性校验被卡住了,只要补上正确的密钥或修正源的签名配置,更新流程就能恢复。

Ubuntu更新时提示GPG error签名错误怎么修复?

先分清 NO_PUBKEY 和 EXPKEYSIG 的区别

NO_PUBKEY 是实际使用中最常见的一类报错。它的含义是:APT 在验证软件源 Release 文件的签名时,发现本地系统里根本没有能验证该签名的公钥。这种情况通常出现在用户手动添加了第三方软件源或者 PPA 之后,只写入了 deb 行,却没有执行对应的密钥导入步骤,或者导入时写错了密钥 ID。还有一种可能是导入了密钥,但密钥存放在了一个不被 APT 检查的位置,导致 apt update 仍然找不到。

EXPKEYSIG 则属于另一类问题:公钥确实存在,但已经超过其有效期,签名无法通过时间校验。这种错误常见于长期没有更新的第三方源,或者软件源维护者更换了签名密钥,而用户本地还保留着旧公钥。此时 apt 会提示 EXPKEYSIG 或 KEYEXPIRED,后面依然会给出十六进制密钥 ID。和 NO_PUBKEY 相比,EXPKEYSIG 的解决方法不是单纯补一个密钥,而是需要先把过期密钥清理掉,再导入新的公钥。

除了这两种,有时候还会看到 BADSIG,它表示签名数据已经损坏,可能是下载过程出错或本地缓存异常。判断时最关键的字段就是报错行末尾的十六进制字符串,后续所有操作都围绕这个 key ID 展开。可以先用下面这个典型报错来熟悉一下格式:

W: GPG error: https://ipipp.com stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 3B4FE6ACC0B21F32
E: The repository 'https://ipipp.com stable InRelease' is not signed.

使用 gpg 添加缺失公钥的标准步骤

过去很多教程都会让用户执行 apt-key add 来导入密钥,但这种方式在 Ubuntu 22.04 及更高版本中已经不再推荐,因为 apt-key 会把公钥写入全局信任文件 /etc/apt/trusted.gpg,意味着该密钥对所有软件源都有效,权限过宽。更安全的做法是:为每个第三方源单独生成一个 .gpg 密钥文件,然后在源配置里用 signed-by 显式指定该文件。这样即使某个源出现问题,也不会影响到系统里其他源的签名校验。

操作时先记下报错中的 key ID,例如 3B4FE6ACC0B21F32。然后从 Ubuntu 公共密钥服务器接收这个公钥。如果网络环境对默认端口不友好,可以尝试 hkp://keyserver.ubuntu.com:80。接收成功后,需要把公钥从 GPG 密钥环导出为独立的二进制文件,并放在 /usr/share/keyrings/ 目录下。下面是完整的命令序列:

# 创建 keyrings 目录(如果不存在)
sudo mkdir -p /usr/share/keyrings
# 从 Ubuntu 密钥服务器接收公钥
sudo gpg --keyserver keyserver.ubuntu.com --recv-keys 3B4FE6ACC0B21F32
# 导出为 .gpg 文件,tee 重定向到文件
sudo gpg --export 3B4FE6ACC0B21F32 | sudo tee /usr/share/keyrings/example.gpg >/dev/null

接下来需要编辑对应的软件源文件,通常位于 /etc/apt/sources.list.d/ 目录下。在 deb 行中增加 signed-by 参数,并指向刚刚导出的 .gpg 文件。例如原本的源可能是 https://ipipp.com/apt stable main,修改后应该写成这样:

deb [signed-by=/usr/share/keyrings/example.gpg] https://ipipp.com/apt stable main

signed-by 后面的路径必须是绝对路径,而且文件要真实存在。保存配置后再次运行 sudo apt update,如果之前的 GPG error 是由缺失公钥引起的,现在就应该消失。需要注意的是,不要同时保留旧的全局密钥和新的独立密钥,否则容易造成路径混乱。最好统一采用 signed-by 方式管理所有第三方源。

处理过期密钥和清理旧版 apt-key 遗留项

如果报错类型是 EXPKEYSIG,说明本地已经存在一个过期公钥,此时单纯添加新密钥可能仍然无法通过签名验证。需要先定位过期公钥的存放位置。可以使用 gpg --show-keys 查看某个 .gpg 文件的内容,也可以列出 /etc/apt/trusted.gpg.d/ 下的所有密钥文件。如果是老系统遗留的 apt-key 全局密钥,执行 sudo apt-key list 还能看到部分信息,但 Ubuntu 22.04 以后该命令已从 apt 包中移除,因此更通用的方法是直接检查密钥文件。

确认过期密钥的位置后,处理方式主要有两种。如果密钥位于独立的 keyring 文件里,直接删除这个文件即可,然后按照前面介绍的方法重新导入新公钥。如果密钥被写入了全局信任文件 /etc/apt/trusted.gpg,手动编辑这个二进制文件比较麻烦,可以先用 gpg --export 把其他仍然有效的密钥导出,再重建整个信任文件。不过多数现代第三方源已经不再依赖全局信任文件,所以更推荐的做法是清理掉遗留项,全面切换成 signed-by 模式。

另外,很多用户通过 add-apt-repository 添加过 PPA,移除 PPA 时通常只会删除源文件,而不会自动清理对应的 GPG 密钥。时间一长,/etc/apt/trusted.gpg.d/ 下面会堆积很多已经失效的公钥。可以定期检查,用 sudo gpg --show-keys 核对指纹,删除不再使用的 .gpg 文件。下面几个命令可以帮助定位和清理:

# 列出所有 trusted.gpg.d 下的密钥文件
ls -l /etc/apt/trusted.gpg.d/
# 查看某个 keyring 中的密钥指纹
sudo gpg --show-keys /usr/share/keyrings/example.gpg
# 删除过期密钥文件
sudo rm /usr/share/keyrings/old-example.gpg

清理过程中务必确认要删除的文件不再被任何 sources.list 或 sources.list.d 下的源配置引用,否则下次更新会重新出现 NO_PUBKEY 错误。建议删除前后都执行一次 sudo apt update,对比输出变化,以便确认问题是否彻底解决。

预防与验证:更新后如何确认签名正常

完成密钥修复后,不要只凭感觉判断。运行 sudo apt update 时重点关注输出中是否还有 GPG error、NO_PUBKEY 或 EXPKEYSIG 字样。如果仍然提示 BADSIG,可能是本地缓存损坏,可以执行 sudo rm -rf /var/lib/apt/lists/* 清空缓存后再更新。这个命令不会删除已安装的软件,只是清掉下载下来的软件源索引,让 APT 重新获取并校验。

验证密钥的正确性不能只看 key ID,因为理论上存在碰撞的可能。更可靠的办法是使用 sudo gpg --with-fingerprint /usr/share/keyrings/example.gpg 查看完整指纹,并与软件源官方公布的指纹进行人工比对。如果指纹不一致,说明导入的可能不是正确密钥,需要立即删除并重新获取。

良好的源管理习惯能显著降低 GPG error 出现概率。每个第三方源单独使用一个 keyring 文件,不把公钥放进全局 trusted.gpg;记录下每个源的 key ID、添加日期和官方地址;当系统跨大版本升级时,重新确认第三方源是否仍兼容。遇到无法确认可信度的源,可以先用 sudo mv /etc/apt/sources.list.d/example.list /etc/apt/sources.list.d/example.list.bak 临时禁用,保证系统主源更新不受影响,再逐一排查。这样即使某个源挂了或者密钥失效,也不会阻塞整个 apt 更新流程。

广告位 · 文章底部(后台-模块管理替换此区域)