目录
apt 离线源(本地镜像源)搭建经验分享
内网服务器、隔离环境(air-gapped)、CI 构建机经常处于无外网状态,这时 apt install 拉不到包。解决办法是在一台能联网的机器上把官方源镜像到本地,再用 HTTP 或 file:// 让离线机访问。本文记录这套「离线源」从搭建到使用、以及 Ubuntu 新版本和 Kali 等系统的差异做法,照着做基本能一次配通。
一、背景与准备
什么是 apt 离线源:apt 源本质上就是「一堆 .deb 安装包 + Packages 索引文件 + Release/InRelease 签名文件」。客户端执行 apt update 拉索引,apt install 按索引去拉对应的 .deb。所谓离线源,就是把这一整套东西复制到本地(局域网服务器或 U 盘),让离线机从本地地址取,而不是从 archive.ubuntu.com 取。
两个角色:
- 源服务器(能联网):负责镜像官方源,提供 HTTP 或本地目录。
- 客户端(离线/内网):改自己的源地址指向源服务器。
什么时候需要:
- 服务器完全无外网(工控、内网堡垒机)。
- 局域网内有多台机器,不想每台都去公网拉,节省带宽。
- CI/CD 构建节点需要稳定、可复现的包版本。
前置条件:
- 一台能联网的同架构机器做源(本文以 amd64 为例,arm64 同理改架构参数)。
- 客户端与源服务器的发行版版本、架构要一致(给 Ubuntu 24.04 配 22.04 的源会 404)。
- 源服务器上有足够磁盘:Ubuntu 全组件镜像可能上百 GB,按需裁剪。
二、方案选型
| 方案 | 适合场景 | 是否自带签名 | 难度 |
|---|---|---|---|
| apt-mirror | 想完整镜像官方源、懒得管细节 | 保留上游签名 | 低 |
| aptly | 要精简、要快照、要自签名、要可控 | 支持自签名/GPG | 中 |
| dpkg-scanpackages | 只放自己/少量 .deb,极简本地源 | 无(需 trusted=yes) | 低 |
| apt-offline | 没有源服务器,单台离线机临时装包 | 沿用官方签名 | 低 |
下文按「完整镜像(apt-mirror)→ 可控镜像(aptly)→ 极简源(dpkg-scanpackages)」三种服务端做法讲,客户端配置单独一节(含 Ubuntu 新旧标准差异),最后给真正断网场景的 file:// 与 apt-offline 做法。
三、服务端:用 apt-mirror 搭建完整离线源(Ubuntu 示例)
适合「把整个 Ubuntu 源搬回家」的场景,命令最少。
bash# 1) 在源服务器上安装 apt-mirror
sudo apt update
sudo apt install -y apt-mirror
# 2) 编辑配置 /etc/apt/mirror.list
sudo cp /etc/apt/mirror.list /etc/apt/mirror.list.bak
/etc/apt/mirror.list 关键配置(以 Ubuntu 24.04 = noble 为例,只镜像 amd64 主用组件,避免爆盘):
bash############# config ##############
set base_path /srv/apt-mirror
set mirror_path $base_path/mirror
set skel_path $base_path/skel
set var_path $base_path/var
set defaultarch amd64
set postmirror_script $var_path/postmirror.sh
set run_postmirror 0
############# mirrors ##############
deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-security main restricted universe multiverse
clean http://archive.ubuntu.com/ubuntu
bash# 3) 执行镜像(首次拉取很大、很慢,放后台跑)
sudo apt-mirror
# 镜像完成后内容在 /srv/apt-mirror/mirror/archive.ubuntu.com/ubuntu
# 4) 用 Nginx 把该目录暴露成 HTTP 源
sudo apt install -y nginx
Nginx 站点配置(把 ubuntu 目录作为 web 根,客户端地址就干净了):
nginxserver { listen 80; server_name _; root /srv/apt-mirror/mirror/archive.ubuntu.com/ubuntu; location / { autoindex on; } }
bashsudo ln -s /etc/nginx/sites-available/apt-mirror /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
此时源地址为 http://<源服务器IP>/ubuntu。可选:把 apt-mirror 放进 cron 定期同步(0 3 * * * root /usr/bin/apt-mirror)。
四、服务端:用 aptly 搭建(推荐,可控 + 可签名)
apt-mirror 是「整盘照抄」,aptly 则可以按需挑选、做快照、还能用你自己的 GPG 密钥签名,更适合对版本有要求的生产环境。
bash# 1) 安装 aptly(Ubuntu/Debian 源里就有)
sudo apt install -y aptly
# 2) 创建并同步一个镜像(noble + 常用组件,仅 amd64)
aptly mirror create -architectures=amd64 ubuntu-noble http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
aptly mirror update ubuntu-noble
# 3) 打个快照(以后升级时基于快照,可回滚)
aptly snapshot create ubuntu-noble-snap from mirror ubuntu-noble
# 4) 发布快照,带发布前缀 ubuntu,distribution 设为 noble
aptly publish snapshot -distribution=noble ubuntu-noble-snap ubuntu
# 发布产物在 ~/.aptly/public/ubuntu
发布后内容在 ~/.aptly/public,直接暴露即可:
bashsudo apt install -y nginx
nginxserver { listen 80; server_name _; root /home/<你的用户>/.aptly/public; location / { autoindex on; } }
客户端源地址即 http://<源服务器IP>/ubuntu,Suites: noble。
想用自签名:先
gpg --gen-key生成密钥,发布时加-keyring/--passphrase相关参数,aptly 会生成InRelease签名;客户端用Signed-By指向你导出的公钥 keyring。若只是内网测试不想管密钥,可用后文的Trusted: yes临时跳过校验(不安全,仅内网验证用)。
五、服务端:极简本地源(dpkg-scanpackages)
只打算放几个自己编译/下载的 .deb(比如离线装 Docker、离线装某个内部包),不需要镜像整个官方源。
bash# 1) 建目录并放入 .deb
sudo mkdir -p /srv/local-deb
sudo cp *.deb /srv/local-deb/
# 2) 生成 Packages 索引
cd /srv/local-deb
dpkg-scanpackages . /dev/null > Packages
gzip -k Packages # 同时生成 Packages.gz,apt 优先用压缩版
# 3) 用 Nginx 暴露(root 指向 /srv/local-deb)
# 客户端用 deb http://<IP>/ / 即可(见第六章 旧格式 flat 写法)
这种「扁平源」没有 dist/component 层级,客户端配置见第六章末尾说明。
六、客户端配置(重点:Ubuntu 新旧标准 + Kali)
这是本文最关键的一节。Ubuntu 24.04 起默认用 DEB822 格式(文件在 /etc/apt/sources.list.d/ubuntu.sources),而 22.04 及以前用传统的单行 /etc/apt/sources.list。两者字段完全不同,配错就 404。
6.1 Ubuntu 24.04+(DEB822 新标准)
新建 /etc/apt/sources.list.d/local.sources(不要碰系统默认的 ubuntu.sources,可以禁用它):
bash# 禁用系统默认公网源(可选)
sudo mv /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.disabled 2>/dev/null
sudo tee /etc/apt/sources.list.d/local.sources > /dev/null <<'EOF'
Types: deb
URIs: http://192.168.1.10/ubuntu
Suites: noble noble-updates noble-security
Components: main restricted universe multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
EOF
要点:
Types: deb对应旧的deb开头。URIs就是源的 HTTP 地址(apt-mirror/aptly 暴露出来的那个)。Suites对应旧格式的「发行版代号」,如noble(24.04) /jammy(22.04) /resolute(26.04)。Components对应旧格式的main restricted universe multiverse。Signed-By:务必保留。因为 apt-mirror 镜像的是上游、签名仍是 Ubuntu 官方密钥,所以这里继续用/usr/share/keyrings/ubuntu-archive-keyring.gpg。若你用 aptly 自签名,则改成你导出的 keyring 路径;内网临时验证可改成Trusted: yes(跳过校验,不安全)。
版本代号别写错:26.04=resolute、24.04=noble、22.04=jammy、20.04=focal。写错会直接 404。
6.2 Ubuntu 22.04 及以前(传统单行格式)
直接编辑 /etc/apt/sources.list:
bashsudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo sed -i 's|^deb |#deb |g' /etc/apt/sources.list # 先注释掉公网源
sudo tee -a /etc/apt/sources.list > /dev/null <<'EOF'
deb http://192.168.1.10/ubuntu noble main restricted universe multiverse
deb http://192.168.1.10/ubuntu noble-updates main restricted universe multiverse
deb http://192.168.1.10/ubuntu noble-security main restricted universe multiverse
EOF
6.3 Kali Linux
Kali 基于 Debian,传统用单行格式,仓库名是 kali-rolling:
bashsudo cp /etc/apt/sources.list /etc/apt/sources.list.bak
sudo tee /etc/apt/sources.list > /dev/null <<'EOF'
deb http://192.168.1.10/kali kali-rolling main non-free non-free-firmware
EOF
服务端需先镜像 Kali 源(在源服务器上把下面这行加进 mirror.list 或用 aptly):
bashdeb http://kali.download/kali kali-rolling main non-free non-free-firmware
Kali 的签名密钥在 /usr/share/keyrings/kali-archive-keyring.gpg;用 DEB822 时 Signed-By 指向它即可。注意 Kali 新版滚动源组件含 non-free-firmware,漏写会报错。
6.4 Debian
Debian 12(bookworm)仍主要用单行格式:
bashdeb http://192.168.1.10/debian bookworm main contrib non-free non-free-firmware deb http://192.168.1.10/debian-security bookworm-security main contrib non-free non-free-firmware
Debian 12+ 同样支持 DEB822(/etc/apt/sources.list.d/debian.sources),字段与 Ubuntu 一致。值得一提的是,最原始的离线源就是 Debian 安装盘的 CD-ROM 源——deb cdrom:[Debian GNU/Linux ...]/ stable main,插盘即可 apt install,本质是同一套本地索引机制。
6.5 扁平本地源(dpkg-scanpackages 产物)的客户端写法
扁平源没有 dist/component 层级,旧格式一行搞定:
bashdeb [trusted=yes] http://192.168.1.10/ /
([trusted=yes] 是因为这种源通常没签名;若你有签名 keyring,换成 [signed-by=/path/to/key.gpg]。)
七、真正断网(air-gapped)场景
前面都是「源服务器在内网、客户端在另一台内网机」。如果客户端压根连不上源服务器(完全物理隔离),有两种做法。
7.1 把整个镜像目录用 U 盘搬过去,用 file:// 挂载
在离线机上把 U 盘内容放到 /srv/apt-mirror/mirror/archive.ubuntu.com/ubuntu,然后客户端用 file://:
DEB822(/etc/apt/sources.list.d/local.sources):
bashTypes: deb URIs: file:///srv/apt-mirror/mirror/archive.ubuntu.com/ubuntu Suites: noble noble-updates noble-security Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg
旧格式:
bashdeb file:///srv/apt-mirror/mirror/archive.ubuntu.com/ubuntu noble main restricted universe multiverse
7.2 单台离线机装包:apt-offline(不搭源)
没有源服务器、只想临时给一台离线机装个包,用 apt-offline 在离线机生成「需求清单」,搬到联网机下载,再搬回来装:
bash# 离线机上:生成需求签名(同时可包含 apt update 需求)
apt-offline set /tmp/need.sig --install vim --update
# 把 /tmp/need.sig 拷到联网机,下载成压缩包
apt-offline get /tmp/need.sig --download /tmp/bundle.zip
# 把 /tmp/bundle.zip 拷回离线机,安装
apt-offline install /tmp/bundle.zip
# 之后直接 apt install vim 即可(包已在本地缓存)
八、验证
在客户端执行:
bashsudo apt update
# 正常应看到从 http://192.168.1.10/... 拉取,无 404/签名报错
apt-cache policy vim
# 输出里 "***" 指向的源应为你的本地地址,说明客户端确实在走离线源
sudo apt install -y vim # 实测安装一个包验证
九、排错速查
| 现象 | 原因 | 处理 |
|---|---|---|
404 Not Found / Unable to locate package | Suites 代号写错(resolute/noble/jammy/bookworm/kali-rolling 混淆),或 Components 拼错 | 核对版本代号与组件名,重新 apt update |
NO_PUBKEY / GPG 签名错误 | Signed-By 路径错、keyring 缺失,或 aptly 自签名未导入客户端 | 指对 keyring 路径;或用 sudo apt install --reinstall ubuntu-keyring 修复官方密钥;内网测试可临时 Trusted: yes |
apt update 卡住/超时 | 源服务器 Nginx 没起、防火墙挡 80、URIs 路径不对 | 源服务器 curl -I http://127.0.0.1/ubuntu 自测;客户端 ping/telnet 通不通 |
架构不匹配(amd64 vs arm64) | 源是 amd64 镜的,客户端是 arm64 | 镜像时加对应架构;或客户端换对应架构源 |
| 磁盘爆满 | apt-mirror 全组件镜像太大 | mirror.list 只保留需要的组件,或改用 aptly 按需快照 |
InRelease 被忽略 / not signed | 扁平源没签名又没加 trusted=yes | 旧格式加 [trusted=yes],DEB822 加 Trusted: yes(仅内网友善环境) |
十、小结与参考资料
搭建 apt 离线源的核心就三步:源服务器镜像官方源 → 用 HTTP(或 U 盘 file://)暴露 → 客户端改源地址指向它。Ubuntu 24.04+ 必须按 DEB822 格式写 *.sources(字段 Types/URIs/Suites/Components/Signed-By),老版本和 Kali/Debian 仍用单行 deb http://... 格式,两者别混。完全断网时用 file:// 或 apt-offline 搬运即可。
参考资料:
- 《新装 Ubuntu 26.04 LTS 换源终极指南:阿里云/华为云 DEB822 配置教程》(ClawLoader,知识库「Linux运维」)——DEB822 字段结构与版本代号对照。
- 《CentOS 系统更换阿里云 yum 源 & Debian 系统更换 APT 源》(知识库「Linux运维」)——传统单行 APT 源写法与
sed替换思路。
ai协作,人工编辑