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

修复 apt 源重复配置与 .list、.sources 文件冲突

apt update 报告“Target is configured multiple times”?本文解释 Ubuntu 24.04+ 中 .list 与 deb822 .sources 重复的原因,并指导您保留一个文件,恢复干净更新。

重复 apt 源错误的含义

重复的 apt 源表示同一个软件仓库在两个不同文件中被声明了两次,APT(高级软件包工具)找到了这两份声明。在 Ubuntu 24.04 及更高版本中,这几乎总是因为第三方安装脚本写入了旧式单行 .list 文件,而磁盘上已经存在同一软件仓库的 deb822 .sources 文件。没有任何文件损坏,也没有软件包面临风险。删除其中一份声明后,消息就会消失。

这是人们通常粘贴到搜索框中的内容:

W: Target Packages (stable/binary-amd64/Packages) is configured multiple times in /etc/apt/sources.list.d/docker.list:1 and /etc/apt/sources.list.d/docker.sources:1

从末尾开始阅读。两个文件分别在某一行声明了同一内容。Target Packages 是 apt 下载的索引,用于了解软件仓库提供哪些软件包;stable/binary-amd64/Packages 指定该索引涵盖的组件(stable)和架构(amd64)。因此,apt 告诉你:stable 组件的 amd64 索引在 docker.list 的第 1 行配置了一次,又在 docker.sources 的第 1 行配置了一次。

在 apt 3.0 及更高版本中,也就是 Ubuntu 25.04 及更高版本和 Debian 13 中,同一消息以 Warning: 开头,而不是 W:。前缀之后的文本相同。

这个警告属于较轻的情况。apt 会合并这两份声明,更新仍会执行,因为两份声明描述的是使用同一密钥的同一存档。严重的情况会停止所有操作:

E: Conflicting values set for option Signed-By regarding source https://download.docker.com/linux/ubuntu/ noble: /usr/share/keyrings/docker-archive-keyring.gpg != /etc/apt/keyrings/docker.asc
E: The list of sources could not be read.

这里 apt 会拒绝继续,因为两份声明为同一存档指定了不同的签名密钥。它会合并两份完全相同的声明,但不会在两个 Signed-By 值之间进行选择,因为选错密钥就意味着使用存档所有者从未用于签名的密钥验证软件包签名。因此,apt 完全不会读取软件源。apt update 和 apt install 都会因这两行相同的错误而失败,直到你手动编辑这些文件。

重复项是如何产生的

这两种格式位于扩展名不同的独立文件中,因此文件系统不会阻止它们同时存在。apt 会在展开每个源文件、生成计划下载的索引目标列表时,才发现两者重叠。在此之前,docker.list 和 docker.sources 是两个互不相关的文件。

以下 4 个常见事件会产生这对文件:

  • 供应商安装脚本,或从旧文章中复制的命令,使用 tee 行写入 /etc/apt/sources.list.d/vendor.list。
  • 供应商自己的软件包随后发布 /etc/apt/sources.list.d/vendor.sources,并自动为您安装该文件。
  • Ubuntu 24.04 及更高版本中的 add-apt-repository 会写入 deb822 格式的 .sources 文件,因此您之前手动以 .list 形式添加的 PPA(个人软件包存档)会以 .sources 的形式重新出现。
  • 发行版升级将发行版自己的软件源改写为 deb822 格式,但保留您手写的 .list 文件,使其与新文件并列存在。

每条路径单独发生时都合理。重复项通常是其中两条路径在同一台服务器上发生的结果,而且两次发生之间可能相隔数月。

两种格式并列对比

旧格式每个软件源占一行,其中每个部分都由位置决定含义。

deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu noble stable

顺序是固定的:类型(deb 表示二进制软件包,deb-src 表示源代码软件包)、方括号中的选项、存档的 URI(统一资源标识符)、套件,以及一个或多个组件。由于字段含义由位置决定,空格位置错误就会改变 apt 的解析结果。

deb822 将相同内容表示为由命名字段组成的段落。该名称来自 RFC 822,即 Debian 已用于软件包控制文件的邮件头格式。

Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: noble
Components: stable
Architectures: amd64
Signed-By: /etc/apt/keyrings/docker.asc

软件源相同,密钥相同,没有添加任何内容。映射关系是直接的:deb 变为 Types,存档地址变为 URIs,套件变为 Suites,组件变为 Components;每个方括号选项则变为单独的字段,因此 signed-by= 变为 Signed-By:,arch= 变为 Architectures:。

每个字段名都使用复数形式,因为每个字段都接受以空格分隔的列表。一个段落中的 Suites: noble noble-updates noble-backports 会替代三行独立的 deb。空行表示一个段落结束,因此单个 .sources 文件可以包含多个软件源。deb822 还支持单行格式难以处理的设置:使用 Enabled: no 停用软件源、使用 Trusted、Check-Valid-Until,以及将内联密钥直接粘贴到 Signed-By 中;其中每行缩进一个空格,空行写成单独的点号。

各文件的位置

  • /etc/apt/sources.list:原始的单文件配置。在 Ubuntu 24.04 及更高版本中,它通常为空,或只包含指向新位置的注释。
  • /etc/apt/sources.list.d/*.list:每行一个条目,通常每个软件源对应一个文件。
  • /etc/apt/sources.list.d/*.sources:deb822 配置段。Ubuntu 24.04 及更高版本将发行版自带的软件源保存在这里的 ubuntu.sources 中。
  • /etc/apt/keyrings/:您添加的密钥应放在这里。/usr/share/keyrings/ 保存软件包提供的密钥。

apt 只读取以 .list 或 .sources 结尾的文件,并且文件名只能包含字母、数字、下划线、连字符和句点。使用其他扩展名的文件会被跳过,并显示通知。这一点与下面的修复方法有关。

查找重复项

从目录列表开始:

ls -l /etc/apt/sources.list.d/
-rw-r--r-- 1 root root  195 Aug  3 09:12 docker.list
-rw-r--r-- 1 root root  254 Aug  9 14:40 docker.sources
-rw-r--r-- 1 root root 2683 Jun 11 08:02 ubuntu.sources

两个文件具有相同的主文件名和不同的扩展名,通常就是成对的配置文件,但不要只相信文件名。请读取文件内容,因为重复项可能隐藏在任意名称的文件中:

grep -rn -E '^(deb |deb-src |Types:|URIs:|Suites:|Signed-By:)' /etc/apt/sources.list /etc/apt/sources.list.d/
/etc/apt/sources.list.d/docker.list:1:deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu noble stable
/etc/apt/sources.list.d/docker.sources:1:Types: deb
/etc/apt/sources.list.d/docker.sources:2:URIs: https://download.docker.com/linux/ubuntu
/etc/apt/sources.list.d/docker.sources:3:Suites: noble
/etc/apt/sources.list.d/docker.sources:6:Signed-By: /etc/apt/keyrings/docker.asc

这两个条目具有相同的主机和相同的软件套件。它们都指向 https://download.docker.com/linux/ubuntu 和套件 noble,因此实际上是同一个软件源的重复配置。它们的 Signed-By 路径也不一致,这正是之前显示 Conflicting values 错误的原因。

此步骤应使用 grep,而不是 apt 命令。apt 已因冲突停止运行时,也无法列出软件源,因此 apt-cache policy 只会输出相同的错误,而不是所需的结果。

修复方法:保留 deb822 文件,移除旧格式文件

保留 .sources 文件。这是 apt 工具目前写入的格式,也是 Debian 和 Ubuntu 的发展方向。删除任何文件前,先检查磁盘上是否存在这两个关键路径中的哪个:

ls -l /etc/apt/keyrings/ /usr/share/keyrings/ | grep -i docker
-rw-r--r-- 1 root root 4813 Aug  9 14:40 docker.asc

当前只有 /etc/apt/keyrings/docker.asc 存在,因此 deb822 文件中的配置有效,而 .list 文件指向的密钥已经被删除。如果最终要保留的文件引用了缺失的密钥,先将可用路径写入该文件,再删除另一个文件。

将旧格式文件移出该目录,不要直接删除:

sudo mkdir -p /root/apt-sources-backup
sudo mv /etc/apt/sources.list.d/docker.list /root/apt-sources-backup/
sudo apt update

也可以将其重命名为 docker.list.bak 并保留在原位置,因为 apt 会忽略未知扩展名。但这样每次运行 apt 都会显示以下提示:

N: Ignoring file 'docker.list.bak' in directory '/etc/apt/sources.list.d/' as it has an invalid filename extension

将文件移到其他位置可以避免在屏幕上显示该提示,同时保留备份。之后,正常的 apt update 应如下所示,且不应有一行同时列出两个文件:

Hit:1 http://archive.ubuntu.com/ubuntu noble InRelease
Get:2 https://download.docker.com/linux/ubuntu noble InRelease [48.8 kB]
Get:3 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Fetched 175 kB in 1s (146 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
All packages are up to date.

现在确认修改后仓库仍然可用:

apt-cache policy | grep download.docker.com
 500 https://download.docker.com/linux/ubuntu noble/stable amd64 Packages
     origin download.docker.com

如果供应商的文档仍假定使用单行文件,可以保留该文件,改为删除 .sources 文件。无论采用哪种方式,都必须遵守同一条规则:同一个 archive 和 suite 只能由一个文件声明。

为什么一个损坏的第三方源会导致 apt update 失败

相邻的故障表现不同,但根因相同:apt 无法使用某个第三方源。第一种情况是缺少密钥:

Err:5 https://download.docker.com/linux/ubuntu noble InRelease
  The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7EA0A9C3F273FCD8
E: The repository 'https://download.docker.com/linux/ubuntu noble InRelease' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.

Signed-By 字段缺失,或指向的文件不是可用的密钥,因此 apt 无法验证存档的 InRelease 文件签名。apt 随后会丢弃整个软件仓库,而不是信任无法验证的软件包列表。先检查密钥文件本身:

ls -l /etc/apt/keyrings/docker.asc
gpg --show-keys /etc/apt/keyrings/docker.asc

有效的密钥会输出包含密钥 ID 的 pub 行,以及标识供应商的 uid 行。gpg: no valid OpenPGP data found. 表示该文件根本不是密钥。通常这是因为密钥 URL 已更改,下载保存的是错误页面。重新获取密钥,检查文件,然后运行 apt update。

第二种情况会在发行版升级后出现:

Err:6 https://ppa.launchpadcontent.net/ondrej/php/ubuntu plucky InRelease
  404  Not Found [IP: 10.0.0.80 443]
E: The repository 'https://ppa.launchpadcontent.net/ondrej/php/ubuntu plucky Release' does not have a Release file.

该 PPA 没有为此套件发布任何内容,因此服务器上不存在对应路径,请求返回 404。其他软件仓库仍会更新,系统中已有的软件包也不会受到影响。不过,此次运行仍会以非零状态退出,因此任何检查 apt update 退出状态的脚本每次运行都会报告失败。这就是在配置了 无人值守安全升级 的服务器上,应该清理失效源的原因:每日产生的噪声会掩盖真正的故障。供应商安装脚本可能遇到这两种情况,因此大多数 Ubuntu 上的 Tailscale 安装错误 最终都源于脚本没有写入密钥环,或存档不支持该发行版代号。

禁用一个源而不影响其他源

对于 deb822 文件,在对应段落中添加一个字段,然后保存:

Types: deb
URIs: https://ppa.launchpadcontent.net/ondrej/php/ubuntu
Suites: plucky
Components: main
Signed-By: /etc/apt/keyrings/ondrej-php.asc
Enabled: no

apt 手册建议使用这种方式,而不是注释掉段落中的每一行。恢复设置也更简单。对于单行文件,在行首添加 #。无论使用哪种格式,将文件移出 /etc/apt/sources.list.d/ 目录也可以禁用该源。如果仓库已永久废弃,应选择这种方式。

再次运行 sudo apt update。该仓库对应的 Err: 块会消失,退出状态也会恢复为 0。下一行可以使用 echo $? 检查退出状态。

不要使用 sudo rm /etc/apt/sources.list.d/* 修复损坏的软件源。在 Ubuntu 24.04 及更高版本中,该命令会删除 ubuntu.sources。该目录包含发行版自带的软件仓库,因此 apt 会完全失去软件包列表,并对实际存在的软件报告 E: Unable to locate package curl。如果已经运行了该命令,请重新写入该文件:

Types: deb
URIs: http://archive.ubuntu.com/ubuntu/
Suites: noble noble-updates noble-backports
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

将其保存为 /etc/apt/sources.list.d/ubuntu.sources,把 noble 替换为从 lsb_release -cs 中获取的发行版名称,然后运行 sudo apt update。

将旧版 .list 文件转换为 deb822

截至 2026 年 8 月,apt 3.0 及更高版本已提供转换工具。Debian 13 包含该工具,Ubuntu 25.04 及其后续每个版本也都包含,包括 26.04。先检查版本,然后运行以下命令:

apt --version
sudo apt modernize-sources

该命令会将 /etc/apt/sources.list.d/ 下的单行文件重写为 deb822 .sources 文件。先阅读命令输出,然后自行列出该目录,并运行 apt update,确认结果无误后再信任转换结果。Ubuntu 24.04 附带较旧版本的 apt,不包含此子命令,在该版本中,该命令会返回 E: Invalid operation modernize-sources。在此版本上,请根据上面的字段映射手动转换。

目前转换并非必需,因为 apt 仍会读取这两种格式。如果服务器计划长期使用,建议进行转换,因为现在所有会写入源配置的工具都会写入 deb822;而只包含 .sources 文件的服务器不会产生这类重复配置。

在服务器上规范管理第三方源

第三方软件仓库是服务器中最容易老化的部分。每个仓库都依赖其维护者继续为您的 Ubuntu 版本发布软件包,而版本升级会在同一时间检验这些承诺是否仍然有效。

  • 只有在发行版软件包无法满足需求时,才添加第三方仓库。普通的 Ubuntu 24.04 LAMP 栈不需要第三方仓库:Ubuntu 软件源已包含其使用的全部软件包,并在该版本的支持期内提供安全更新。
  • 将密钥存放在 /etc/apt/keyrings/ 中,每个供应商使用一个文件,权限设为 644。非特权 _apt 用户负责下载,并且必须能够读取密钥;如果密钥文件只有 root 可读,那么每次从该仓库获取软件包时都会出现权限错误。
  • 在每个源配置段中,让 Signed-By 指向该确切文件。存放在 /etc/apt/trusted.gpg 或 /etc/apt/trusted.gpg.d/ 中的密钥会对服务器上的所有仓库生效。这意味着多年前添加的供应商密钥可能验证来自任意位置的软件包。
  • 在版本升级前,读取软件源配置,并确认每个供应商已经为您要升级到的 suite 发布软件包。

旧的全局密钥环中的密钥会在每次更新时触发提示:

W: https://download.docker.com/linux/ubuntu/dists/noble/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.

将该密钥导出到独立文件,然后让源配置段指向该文件:

gpg --no-default-keyring --keyring /etc/apt/trusted.gpg --export 7EA0A9C3F273FCD8 | sudo tee /etc/apt/keyrings/docker.gpg > /dev/null
sudo chmod 644 /etc/apt/keyrings/docker.gpg

将 Signed-By: /etc/apt/keyrings/docker.gpg 添加到仓库的配置段中,然后运行 sudo apt update。当没有仓库再依赖旧密钥环后,警告就会停止;随后可以使用 sudo gpg --no-default-keyring --keyring /etc/apt/trusted.gpg --delete-key 7EA0A9C3F273FCD8 删除该条目。

还有一个习惯可以避免最多的问题。do-release-upgrade 会在升级期间禁用第三方源,并在升级完成后继续保持禁用状态。之后手动逐个启用这些源时,最容易创建重复配置。开始前请阅读Ubuntu 24.04 到 26.04 的升级指南,并记录仍然需要哪些仓库。对于刚刚完成构建的机器,设置软件源的最佳时机是新 VPS 上线后的前十分钟,因为此时服务器上只有 Ubuntu 自带的源。

FAQ

为什么 apt 提示某个目标被配置了多次?

因为 /etc/apt/sources.list.d/ 下的两个文件声明了相同的存储库、套件和组件。消息会列出这两个文件及其行号,例如 docker.list:1 和 docker.sources:1。apt 会合并这些配置并继续执行,因此更新操作本身仍然可以完成。不过,仍应清理重复配置:只要两个文件指定了不同的签名密钥,apt 就会停止并显示 E: Conflicting values set for option Signed-By,拒绝读取任何软件源,这也会阻止 apt install。

应该保留 .list 文件还是 .sources 文件?

保留 .sources 文件。Ubuntu 24.04 及更高版本由 add-apt-repository 写入 deb822 格式。该格式为每个设置使用一个命名字段,而不是在方括号中使用位置固定的文本,也是发行版未来采用的格式。删除 .list 文件前,使用 ls -l /etc/apt/keyrings/ 确认 .sources 文件中的 Signed-By 路径指向一个实际存在的密钥。将旧文件移出 /etc/apt/sources.list.d/,不要在该目录内重命名,因为残留的 .bak 文件名会导致 apt 每次运行都打印忽略文件的提示。

如何禁用某个 apt 软件源而不删除它?

在 deb822 .sources 文件中,将 Enabled: no 添加到该段配置中。在单行格式的 .list 文件中,将 # 放在该行开头。无论采用哪种方式,之后都运行 sudo apt update,该软件源对应的 Err: 块就会消失。当第三方软件源尚未为你的 Ubuntu 版本提供软件包,且其 404 错误导致 apt update 以非零状态退出时,应采用这种方式。

单行 sources.list 格式会被弃用吗?

该格式已弃用,但尚未移除。apt 仍会读取 .list 文件,并且在很长一段时间内都会继续支持,因此你的服务器不会在明天突然出现故障。新的工具会写入 deb822 格式:Ubuntu 24.04 及更高版本将发行版软件源保存在 /etc/apt/sources.list.d/ubuntu.sources 中,而 add-apt-repository 会写入 .sources 文件。在 apt 3.0 及更高版本中,sudo apt modernize-sources 可转换现有文件。

#apt#ubuntu#deb822#package-management#troubleshooting