title: 使用 Ubuntu ISO 镜像搭建本地 APT 源
tags: [Ubuntu, APT, 本地源, ISO, 系统管理, 离线部署]
使用 Ubuntu ISO 镜像搭建本地 APT 源
在内网服务器、离线环境或需要频繁重装系统的场景下,从官方软件源下载软件包往往速度缓慢甚至不可用。利用 Ubuntu 的 ISO 安装镜像搭建本地 APT 源,是一种轻量、可靠、无需持续联网的解决方案——不需要复杂的仓库同步工具,只需一张 ISO 镜像和几行配置即可。
本文将详细介绍如何挂载 Ubuntu ISO 镜像、配置本地 APT 源、集成外部软件包,以及在生产环境中落地的最佳实践。
核心概念
APT 源的工作原理
Ubuntu 的 APT (Advanced Package Tool) 从 /etc/apt/sources.list 和 /etc/apt/sources.list.d/ 目录下的配置文件中读取软件源地址。每个源指向一个包含 Packages.gz(包索引)和 .deb 安装包的目录结构。apt update 会下载这些索引,apt install 则根据索引下载对应的 .deb 包。
ISO 镜像中的软件包结构
Ubuntu 的 ISO 安装镜像内置了 pool/ 目录,其中包含大量 .deb 软件包,以及 dists/ 目录下的 Release、Packages 索引文件。这些文件本身就是标准的 APT 源结构,可以直接被 APT 使用。
ISO 挂载点
├── dists/
│ ├── jammy/ # 发行版代号
│ │ ├── Release
│ │ ├── main/
│ │ │ └── binary-amd64/
│ │ │ └── Packages.gz
│ │ ├── universe/
│ │ └── restricted/
│ └── ...
└── pool/
├── main/
├── universe/
└── restricted/
三种方案对比
| 方案 | 复杂度 | 磁盘占用 | 是否需联网 | 推荐场景 |
|---|---|---|---|---|
| ISO 直接挂载 | 低 | ~4.5 GB | 否 | 单机临时使用 |
| ISO 拷贝到硬盘 | 低 | ~4.5 GB | 否 | 多台服务器共享 |
| apt-mirror 完整同步 | 高 | 100+ GB | 首次需要 | 企业级永久源 |
实战步骤
步骤一:下载 Ubuntu ISO 镜像
首先获取所需的 Ubuntu ISO 镜像。推荐使用国内的镜像站加速下载。
# 下载 Ubuntu 22.04 LTS (Jammy) Server 镜像(清华源)
wget -c https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04.5/ubuntu-22.04.5-live-server-amd64.iso
-O /opt/iso/ubuntu-22.04.5-live-server-amd64.iso
# 下载 Desktop 版(包含更多桌面软件包)
wget -c https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04.5/ubuntu-22.04.5-desktop-amd64.iso
-O /opt/iso/ubuntu-22.04.5-desktop-amd64.iso
# 下载 SHA256 校验文件
wget https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/22.04.5/SHA256SUMS
-O /opt/iso/SHA256SUMS
# 校验文件完整性
cd /opt/iso && sha256sum -c --ignore-missing SHA256SUMS
执行结果示例:
ubuntu-22.04.5-live-server-amd64.iso: OK
步骤二:挂载 ISO 镜像
将 ISO 挂载到系统目录,使其内容可读。
# 创建挂载点
mkdir -p /opt/iso/mnt
# 挂载 ISO(loop 设备方式)
mount -o loop /opt/iso/ubuntu-22.04.5-live-server-amd64.iso /opt/iso/mnt
# 验证挂载
ls /opt/iso/mnt/
# 预期输出: boot dists EFI install isolinux md5sum.txt pool preseed README.diskdefines ubuntu
# 查看 dists 目录(确认 APT 源结构)
ls /opt/iso/mnt/dists/
# 预期输出: jammy
注意:mount -o loop 不需要 root 密码吗?实际上需要 root 权限。如果你没有 root 权限,可以使用 sudo 或参考后文的「无 root 权限的替代方案」。
步骤三:配置本地 APT 源
通过 deb file:// 协议将挂载的 ISO 目录配置为 APT 源。
# 备份原始源配置
cp /etc/apt/sources.list /etc/apt/sources.list.backup
# 清除原有源并配置本地 ISO 源
cat > /etc/apt/sources.list << 'EOF'
# 本地 ISO 镜像源(Ubuntu 22.04 Jammy)
deb [trusted=yes] file:///opt/iso/mnt jammy main restricted universe multiverse
EOF
# 更新 APT 缓存
apt update
执行 apt update 后的预期输出:
Hit:1 file:/opt/iso/mnt jammy InRelease
Reading package lists... Done
参数说明:[trusted=yes] 告诉 APT 信任该源的签名(ISO 镜像的 Release 文件可能没有 GPG 签名,或签名与系统 truststore 不匹配)。如果不加此参数,apt update 会报 The repository 'file:///opt/iso/mnt jammy InRelease' is not signed 错误。
步骤四:测试软件包安装
验证本地源是否正常工作。
# 测试安装一个基础包
apt install -y htop
# 测试安装一个开发工具包
apt install -y build-essential
# 安装 Docker(如果 ISO 中包含)
# apt install -y docker.io
验证本地源使用情况:确认软件包确实来自本地 ISO 而非缓存。
# 查看 apt 日志,确认软件包来源
grep "Install: " /var/log/apt/history.log | tail -5
如果 ISO 镜像中不包含某个包,APT 会报错:
Package XXX is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
解决方法:添加备用网络源(见「常见问题」部分)。
步骤五:添加外部软件包到本地源
ISO 镜像中的软件包是有限的。如果需要补充额外包,可以手动下载并重建索引。
# 创建一个目录存放额外包
mkdir -p /opt/iso/extras
# 下载需要的额外包(例如 nginx)
cd /opt/iso/extras
apt download nginx
apt download nginx-common
apt download nginx-core
# 创建 Packages 索引
cd /opt/iso/extras
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz
# 更新 sources.list,添加额外源
cat > /etc/apt/sources.list << 'EOF'
# 本地 ISO 镜像源
deb [trusted=yes] file:///opt/iso/mnt jammy main restricted universe multiverse
# 本地额外包源
deb [trusted=yes] file:///opt/iso/extras ./
EOF
# 更新并验证
apt update
apt install -y nginx
Python 脚本自动化:当需要批量下载大量依赖包时,可以使用以下脚本:
#!/usr/bin/env python3
"""
批量下载软件包及其依赖,用于离线部署。
用法: python3 download-deps.py <package1> <package2> ...
"""
import subprocess
import sys
import os
def get_deps(package):
"""获取指定包的依赖列表"""
result = subprocess.run(
["apt-cache", "depends", package, "--recurse", "--no-recommends",
"--no-suggests", "--no-conflicts", "--no-breaks",
"--no-replaces", "--no-enhances"],
capture_output=True, text=True
)
deps = []
for line in result.stdout.splitlines():
line = line.strip()
if line.startswith("Depends:"):
dep = line.split(":", 1)[1].strip().split()[0]
if dep not in deps and dep != package:
deps.append(dep)
return deps
def download_package(pkg_name, target_dir):
"""下载单个包到目标目录"""
result = subprocess.run(
["apt", "download", pkg_name],
capture_output=True, text=True, cwd=target_dir
)
if result.returncode != 0:
print(f" [WARN] 无法下载 {pkg_name}: {result.stderr.strip()}")
return False
print(f" [OK] {pkg_name}")
return True
def main():
if len(sys.argv) < 2:
print("用法: python3 download-deps.py <package1> <package2> ...")
sys.exit(1)
target_dir = "/opt/iso/extras"
os.makedirs(target_dir, exist_ok=True)
# 收集所有需要下载的包
all_packages = set()
for pkg in sys.argv[1:]:
print(f"分析 {pkg} 的依赖关系...")
all_packages.add(pkg)
for dep in get_deps(pkg):
all_packages.add(dep)
print(f"n共需下载 {len(all_packages)} 个包...")
for pkg in sorted(all_packages):
download_package(pkg, target_dir)
# 重建 Packages 索引
print("n重建 Packages 索引...")
subprocess.run(["dpkg-scanpackages", ".", "/dev/null"],
capture_output=True, cwd=target_dir)
subprocess.run(["gzip", "-9c", "Packages"], capture_output=True, cwd=target_dir)
print("完成!")
if __name__ == "__main__":
main()
步骤六:通过网络共享本地源(多台机器使用)
将 ISO 源通过 HTTP 共享,让局域网内其他机器也能使用。
# 安装 Nginx
apt install -y nginx
# 配置 Nginx 提供 ISO 源
cat > /etc/nginx/sites-available/apt-local << 'NGINX'
server {
listen 80;
server_name _;
root /opt/iso/mnt;
location / {
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
}
# 对索引文件启用压缩传输
location ~ .(gz|bz2)$ {
gzip off;
add_header Content-Encoding gzip;
}
}
NGINX
# 启用站点并重启
ln -sf /etc/nginx/sites-available/apt-local /etc/nginx/sites-enabled/
systemctl restart nginx
# 测试访问
curl -s http://localhost/dists/jammy/Release | head -5
客户端配置:在其他机器上,将源指向这台服务器:
# 在客户端机器上执行
cat > /etc/apt/sources.list << 'EOF'
deb [trusted=yes] http://192.168.1.100 jammy main restricted universe multiverse
EOF
apt update
防火墙配置:如果客户端无法连接,检查服务器防火墙:
ufw allow 80/tcp
# 或
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
步骤七:设置开机自动挂载
让 ISO 挂载在系统重启后自动生效。
# 获取 ISO 的 UUID(用于 /etc/fstab)
blkid /opt/iso/ubuntu-22.04.5-live-server-amd64.iso
# 编辑 /etc/fstab,添加以下行
echo "/opt/iso/ubuntu-22.04.5-live-server-amd64.iso /opt/iso/mnt iso9660 loop,ro,auto 0 0"
>> /etc/fstab
# 测试 fstab 配置
mount -a
# 验证
mount | grep iso
# 预期输出: /opt/iso/ubuntu-22.04.5-live-server-amd64.iso on /opt/iso/mnt type iso9660 (ro,loop)
常见问题
Q1: apt update 报错 “The repository is not signed”
现象:
W: GPG error: file:/opt/iso/mnt jammy InRelease: The following signatures couldn't be verified because the public key is not available.
E: The repository 'file:/opt/iso/mnt jammy InRelease' is not signed.
原因:ISO 镜像的 Release 文件签名不在系统的 GPG truststore 中。
解决方案:在源配置中添加 [trusted=yes] 选项:
deb [trusted=yes] file:///opt/iso/mnt jammy main restricted universe multiverse
Q2: 找不到某个软件包(Package not found)
现象:apt install <package> 提示 E: Unable to locate package <package>
原因:ISO 镜像只包含精选的软件包,并非 Ubuntu 仓库的全部包。Desktop 版比 Server 版包含更多包,但仍有缺失。
解决方案:
1. 确认包名是否在 ISO 中:
bash
# 搜索 ISO 中是否包含该包
ls /opt/iso/mnt/pool/main/ | grep <package>
ls /opt/iso/mnt/pool/universe/ | grep <package>
2. 添加一个网络源作为补充(优先使用本地源,网络源作为后备):
bash
cat > /etc/apt/sources.list << 'EOF'
deb [trusted=yes] file:///opt/iso/mnt jammy main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu jammy main universe restricted multiverse
EOF
apt update
3. 使用 apt-get install --print-uris 获取下载 URL,手动下载后离线安装。
Q3: 挂载 ISO 报 “No medium found”
现象:mount -o loop 报错 mount: /opt/iso/mnt: mount failed: No medium found
原因:ISO 文件路径错误、文件损坏或 loop 设备不足。
解决方案:
# 检查 ISO 文件是否存在且完整
ls -lh /opt/iso/ubuntu-22.04.5-live-server-amd64.iso
file /opt/iso/ubuntu-22.04.5-live-server-amd64.iso
# 预期输出: ISO 9660 CD-ROM filesystem data
# 检查可用 loop 设备
ls -la /dev/loop*
cat /proc/sys/dev/loop/max
# 如果 loop 设备不足,手动分配
losetup -f
# 输出: /dev/loopX
losetup /dev/loopX /opt/iso/ubuntu-22.04.5-live-server-amd64.iso
mount /dev/loopX /opt/iso/mnt
Q4: 如何同时支持多个 Ubuntu 版本?
需求:一台服务器上同时提供 Ubuntu 20.04 (Focal) 和 22.04 (Jammy) 的源。
解决方案:使用不同的挂载点和配置节。
# 创建双版本挂载点
mkdir -p /opt/iso/focal /opt/iso/jammy
# 挂载两个 ISO
mount -o loop /opt/iso/ubuntu-20.04.6-live-server-amd64.iso /opt/iso/focal
mount -o loop /opt/iso/ubuntu-22.04.5-live-server-amd64.iso /opt/iso/jammy
# 配置双源(在 sources.list 中同时配置)
cat > /etc/apt/sources.list << 'EOF'
# 本地 ISO 源 - Ubuntu 20.04 Focal
deb [trusted=yes] file:///opt/iso/focal focal main restricted universe multiverse
# 本地 ISO 源 - Ubuntu 22.04 Jammy
deb [trusted=yes] file:///opt/iso/jammy jammy main restricted universe multiverse
EOF
Q5: 没有 root 权限怎么办?
场景:你使用的是共享服务器或容器,没有 sudo 权限。
解决方案:使用 fakechroot 或 apt-offline 工具。
# 方案一:使用 apt-offline(推荐)
# 在有网络的机器上生成离线包清单
apt-offline set /tmp/offline.sig --install-packages nginx git
# 在目标机器上应用
apt-offline install /tmp/offline.sig
# 方案二:使用 dpkg 手动安装(最轻量)
# 在 ISO 中找到 .deb 包
# 用 dpkg -i 逐个安装(不处理依赖)
dpkg -i /path/to/package.deb
# 方案三:用户级 apt 源(apt 支持用户级源目录)
mkdir -p ~/.local/share/apt-sources
cp -r /opt/iso/mnt/* ~/.local/share/apt-sources/
# 配置用户级源
echo "deb [trusted=yes] file://${HOME}/.local/share/apt-sources jammy main"
> ~/.config/apt/sources.list 2>/dev/null ||
echo "用户级源不受系统 apt 支持,请使用 sudo 或联系管理员"
总结
- ISO 镜像直接挂载是最简单、最快搭建本地 APT 源的方式——挂载、配置 sources.list、apt update 三步即可完成
- 通过
[trusted=yes]解决 ISO 签名问题,通过deb file://协议实现本地源 - 使用
dpkg-scanpackages可以手动添加 ISO 中缺失的软件包到本地源 - 配合 Nginx 可以将本地源共享给局域网内的所有机器,适用于多服务器离线部署场景
- 对于生产环境,建议将 ISO 源与一个有限配额的网络源结合,兼顾覆盖率和离线速度
延伸阅读:
– Ubuntu 官方仓库镜像指南
– apt-mirror 项目 — 完整同步 Ubuntu 仓库
– reprepro — 企业级 APT 仓库管理工具















暂无评论内容