简介:面向企业级Linux运维及IT管理人员的APT内网源搭建指南,聚焦Ubuntu Server 24.04.1环境,旨在解决封闭网络下软件更新慢、过度依赖公网源的问题。该文档为单个PDF文件,仅894KB,篇幅紧凑且覆盖完整流程,已有2026人学习。内容从环境准备开始,区分AMD64与ARM64架构的镜像源差异,分别给出阿里云和清华源的配置方法;重点讲解apt-mirror的安装、mirror.list参数配置,如下载路径、线程数、架构选择,以及同步后clean脚本的清理操作。发布环节使用Nginx,介绍了离线安装依赖deb包的批量命令、软链接创建、默认站点修改及404权限排查;客户端配置则清晰指出编辑sources.list.d文件并将公网源替换为内网IP的具体位置。整体上可支撑运维人员从零搭建私有APT源,提升内网批量部署效率,同时降低外网依赖,保障数据安全。
1. 内网环境下搭一套 Ubuntu APT 源,为什么绕不开 Ubuntu Server 24.04
机房断外网的 Linux 服务器要装软件,最先崩的不是业务,是apt-get install。某次给某公司一批离线环境的 Ubuntu Server 做交付,几十台机器都要装同一批包,挨个dpkg -i本地 deb 文件,依赖缺一个就卡一次,折腾到怀疑人生。后来老老实实搭了一台内网 APT 源服务器,同步好镜像、用 Nginx 发布出去,所有客户端把sources.list指向内网 IP,一条apt update全部拉通。这套东西的核心就是「同步工具 apt-mirror + 发布工具 Nginx」,而承载它的底座,正好是 Ubuntu Server 24.04.1 noble——noble 的仓库结构清楚、apt-mirror 支持顺手,AMD64 和 ARM64 双架构都能同步。本文把这套环境从头到尾拆开,从选源、同步、发布到客户端验证,全部按我实际跑通的步骤写,适合要给内网机器统一交付软件包的运维,也适合第一次搭私有 APT 源的开发者照着抄。
2. 环境准备:Ubuntu Server 24.04.1 与 apt-mirror 安装
2.1 系统版本、架构与网络条件核对
搭建内网 APT 源之前,先确认三件事:系统版本、CPU 架构、这台机器能不能出网。我这边使用的同步机是 Ubuntu Server 24.04.1,内核代号 noble,这是 24.04 系列的长期支持版本,仓库维护周期长,内网源搭一次能用好几年,不太用担心某个发行版组件因为生命周期结束被上游清掉。
架构上要注意,Ubuntu 官方仓库分两套:AMD64 走主仓库,ARM64 走ubuntu-ports。如果内网里两种架构的机器都有,同步机就需要把两套仓库都拉下来,体积会翻倍,这个在磁盘规划时就要算进去。网络条件上,这台同步机至少需要能访问公网镜像站,我一般用阿里云镜像或者 TUNA 清华镜像,国内访问速度稳定,断点续传也正常。
另外提一句,apt-mirror 这个工具只负责把远程仓库的文件抓到本地,不负责给客户端分发。分发的活由 Nginx 干。所以整套环境的角色划分是:同步机(出网抓包) + 发布机(Nginx 对内网提供 HTTP 服务)。如果内网机器少,这两层可以合在一台机器上,我在生产环境就是这么干的。
2.2 安装 apt-mirror 与磁盘空间规划
apt-mirror 在 Ubuntu 官方源里直接有,不需要额外加 PPA。登录到同步机后:
sudo apt update sudo apt-get install -y apt-mirror这里先把apt update跑一遍再装,是避免刚装好的系统索引是空的,直接apt-get install会提示找不到软件包。如果同步机本身只有内网源可用,先把临时外网源加回来装完工具再切走,也是常见做法。
装完之后确认版本:
apt-mirror --version正常会输出版本号,如果没有输出,说明安装有问题,需要重新检查 apt 源。apt-mirror 装好后不会自动创建目录,它要等第一次执行同步时才按配置里的base_path生成目录结构,所以下一步是先规划磁盘。
磁盘规划这块,我踩过坑。noble 的 main/restricted/universe/multiverse 四个组件,加上 security/updates/proposed/backports 五个套件,同步纯 AMD64 架构的二进制包,实际落盘大约几十 GB,如果再加 ARM64 的ubuntu-ports,总量会逼近一百多 GB 甚至更多。所以给/var/spool单独分一个数据盘比较稳妥,避免把系统盘撑爆。
sudo mkdir -p /var/spool/apt-mirror df -h /var/spool/apt-mirrordf -h确认这个目录所在分区的可用空间。我一般要求至少留出预估同步体积的 1.5 倍空间,因为 apt-mirror 同步过程中会有临时索引文件,加上clean.sh清理前的冗余文件,空间不够很容易同步到一半报 disk full。
2.3 搞清楚 base_path 下的目录结构
apt-mirror 默认的base_path是/var/spool/apt-mirror,这个路径下会自动生成四个目录,各有分工:
| 目录 | 作用 |
|---|---|
mirror | 存放实际同步下来的仓库文件,是 Nginx 发布时指向的根目录 |
skel | 存放远程仓库的索引文件,比如 dists 目录下的 Release、Packages 等 |
var | 存放 apt-mirror 运行日志和 clean.sh 清理脚本 |
var/clean.sh | 根据 mirror.list 配置的 clean 行,清理本地已失效的旧包 |
理解这四个目录很关键。Nginx 发布的根目录不是base_path本身,而是$base_path/mirror下按镜像站域名生成的子目录。比如用阿里云源同步,最终仓库文件在/var/spool/apt-mirror/mirror/mirrors.aliyun.com/ubuntu/下面。这个路径后面做软链接时要经常用到,先记熟,省得到时候 404 了才想起目录结构没理清。
3. 配置镜像源:mirror.list 参数拆解与同步执行
3.1 选源:阿里云、中科大与 TUNA 怎么取舍
apt-mirror 的同步源就写在/etc/apt/mirror.list里,选哪个镜像站直接决定同步速度和后续稳定性。我这边环境里试过三个源,简单说下差别。
阿里云镜像(mirrors.aliyun.com)在国内带宽足,同步速度快,noble 的仓库目录完整,主仓库和 security/updates 这些套件都齐全,是我生产环境的首选。中科大源(mirrors.ustc.edu.cn)同样稳定,但有时并发一高速度会波动。TUNA 清华源的帮助文档做得最清楚,AMD64 和 ARM64 的仓库路径区分得很明确——AMD64 看/ubuntu/帮助页,ARM64 看/ubuntu-ports/帮助页,适合第一次搭源的人对着核对路径。
三个源选一个就行,不建议在同一个mirror.list里混着写多个源,因为clean行是跟着源走的,混用会导致 clean 脚本判断失效包时出问题。我一般固定用阿里云:
deb https://mirrors.aliyun.com/ubuntu noble main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-security main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-updates main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-proposed main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-backports main restricted universe multiverse这里每行 URL 后面的noble是发行版代号,不能写成 24.04。main restricted universe multiverse是四个组件,按顺序写全,少了哪个组件客户端apt update就会缺哪部分包。注意这里我没加deb-src,源码包体积大、内网环境基本用不到,省掉能少同步不少数据。
3.2 mirror.list 完整配置与参数说明
打开配置文件:
sudo vim /etc/apt/mirror.list完整配置如下,每条参数后面我标注了作用:
############# config ################## set base_path /var/spool/apt-mirror set mirror_path $base_path/mirror set skel_path $base_path/skel set var_path $base_path/var set cleanscript $var_path/clean.sh set defaultarch amd64 set postmirror_script $var_path/postmirror.sh set run_postmirror 0 set nthreads 20 set _tilde 0 ############# end config ################## deb https://mirrors.aliyun.com/ubuntu noble main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-security main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-updates main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-proposed main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu noble-backports main restricted universe multiverse clean https://mirrors.aliyun.com/ubuntu参数说明:
base_path:镜像文件下载的根路径,默认/var/spool/apt-mirror,一般不用改。mirror_path:实际仓库存放目录,默认是$base_path/mirror。skel_path:临时索引文件目录,就是远程仓库 dists 目录下那些 Release、Packages 索引,默认即可。var_path:日志和 clean 脚本所在目录,默认即可。defaultarch:指定同步的 CPU 架构。默认会同步本机相同架构,比如同步机是 AMD64,它就只下 AMD64 的包。需要同步 ARM64 时,把这个参数改成arm64,或者用单独的 mirror.list 跑两遍。nthreads:下载线程数。我设置为 20,内网出网带宽够的话这个值能让同步速度快不少;但带宽有限的话,线程太高反而容易断连,可以降到 5 到 8。_tilde 0:保持文件原始命名,不做~后缀替换,这个保持默认就行。clean行:对应clean.sh的清理范围,写了哪条源,清理时就只处理哪条源对应路径下失效的包。
如果内网需要同时支持 AMD64 和 ARM64,我一般这样做:先把上面配置跑一遍同步,完成后改defaultarch为arm64,同时把deb行的 URL 从https://mirrors.aliyun.com/ubuntu换成https://mirrors.aliyun.com/ubuntu-ports(ARM64 的仓库路径),再跑一次同步。这样两个架构的仓库都在本地,互相不干扰。
3.3 执行同步与 clean.sh 清理
配置写好后,开始同步:
sudo apt-mirror这里直接前台跑。同步过程中会看到大量下载输出,正常现象。整个同步时长取决于网络和源体积,第一次全量同步花费几小时很正常,期间不要Ctrl+C中断,容易留下不完整的索引文件。
同步结束时会看到类似这样的提示:
Run /var/spool/apt-mirror/var/clean.sh for this purpose意思是提醒你去执行清理脚本,把本地已失效的旧包清掉。按提示操作:
cd /var/spool/apt-mirror/var sudo ./clean.shclean.sh是 apt-mirror 自动生成的,不需要手动编辑。它会读取 mirror.list 里的clean行,把本地仓库里远程已经不存在的文件删掉,避免旧版本包一直堆积占磁盘。
3.4 同步完成后的检查
同步加清理都结束后,别急着配 Nginx,先检查两件事。
第一件,确认仓库目录结构完整:
ls /var/spool/apt-mirror/mirror/mirrors.aliyun.com/ubuntu/dists/正常会看到noble、noble-security、noble-updates等目录。缺哪个,回去检查 mirror.list 里对应的deb行有没有写错。
第二件,确认索引文件不是空的:
ls -lh /var/spool/apt-mirror/mirror/mirrors.aliyun.com/ubuntu/dists/noble/ReleaseRelease文件是客户端apt update时最先拉取的元数据,文件存在且大小正常,说明同步基本靠谱。如果 Releases 文件是 0 字节,多半是同步中断过,需要删掉对应的 skel 索引重跑。
4. 用 Nginx 发布内网源:离线安装与站点映射
4.1 下载 Nginx 1.24.0 与依赖 deb 包
同步机通常和外网隔离,Nginx 也没法直接apt install,所以要先在一台能出网的机器上把 Nginx 和依赖包全部下载成 deb 文件,再拷到同步机上离线安装。我用的是 Ubuntu 官方源里的 Nginx 1.24.0 版本,完整依赖清单如下:
| 文件 | 用途 |
|---|---|
nginx_1.24.0-2ubuntu7.1_amd64.deb | Nginx 主程序包 |
nginx-common_1.24.0-2ubuntu7.1_all.deb | 通用配置与脚本,所有架构共用 |
libnginx-mod-http-geoip_1.24.0-2ubuntu7.1_amd64.deb | GeoIP 模块 |
libnginx-mod-http-image-filter_1.24.0-2ubuntu7.1_amd64.deb | 图片过滤模块 |
libnginx-mod-http-xslt-filter_1.24.0-2ubuntu7.1_amd64.deb | XSLT 过滤模块 |
libnginx-mod-mail_1.24.0-2ubuntu7.1_amd64.deb | 邮件代理模块 |
libnginx-mod-stream_1.24.0-2ubuntu7.1_amd64.deb | 四层流模块 |
libgeoip1t64_1.6.12-11.1build1_amd64.deb | GeoIP 运行库 |
下载这些包很简单,在有外网的 Ubuntu 24.04 机器上执行:
mkdir -p nginxsetup cd nginxsetup apt-get download nginx nginx-common libnginx-mod-http-geoip \ libnginx-mod-http-image-filter libnginx-mod-http-xslt-filter \ libnginx-mod-mail libnginx-mod-stream libgeoip1t64apt-get download只会把指定的 .deb 文件下载到当前目录,不会安装,正好适合离线搬运场景。全部下载完后,把这整个nginxsetup目录拷到同步机上,路径随意,我一般放在/root/nginxsetup。
4.2 批量安装 deb 与 systemd 管理
到了同步机上,进入 deb 目录批量安装:
cd /root/nginxsetup sudo dpkg -i *.debdpkg -i *.deb会把目录下所有 deb 一次性交给 dpkg 处理,它会自动按依赖关系解包安装。如果提示某个依赖不满足,说明有 deb 没下载全,回到有外网的机器上补下对应包再重新执行。出现报错的时候不要急着重启服务,先把依赖补齐。
安装完成后启动服务:
sudo systemctl start nginx sudo systemctl enable nginxstart是立即启动,enable是设置开机自启。两条命令返回没有报错,说明 Nginx 已经跑起来了。用systemctl status nginx看一眼状态是 active (running) 再继续往下走。
4.3 创建软链接并修改 default 站点配置
Nginx 装好了,接下来把同步好的仓库目录映射到 Nginx 的发布目录下。我用的方法是软链接:
sudo ln -s /var/spool/apt-mirror/mirror/mirrors.aliyun.com /var/www/mirror这里软链接的名字mirror是发布路径的一部分,后面客户端源里会用到。注意ln -s的源路径要写对,mirrors.aliyun.com是 apt-mirror 按镜像站域名生成的目录名,少了一层多了一层都会导致软链接指向空路径。
然后修改 Nginx 默认站点配置:
sudo vim /etc/nginx/sites-enabled/default把配置改成下面这样:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www/mirror; autoindex on; autoindex_exact_size off; autoindex_localtime on; server_name _; location / { try_files $uri $uri/ =404; } }配置说明:
root /var/www/mirror:把发布根目录指向软链接。这样http://服务器IP/ubuntu/就能直接访问到仓库里的ubuntu目录。autoindex on:开启目录列表。客户端访问目录时能看到文件列表,浏览器打开也能直观确认源是否发布成功。autoindex_exact_size off让文件大小显示得可读一些,autoindex_localtime on让文件时间按服务器本地时区显示。server_name _:匹配任意 Host 请求,避免因为 Host 头不匹配返回 404。
配置修改后重启:
sudo systemctl restart nginx4.4 验证 Web 发布可访问
重启完在浏览器或者另一台内网机器上访问:
http://<同步机IP>/ubuntu/能看到dists/和pool/目录列表,说明发布成功。如果看到的是 Nginx 欢迎页或 403,多半是root路径不对,回上一步检查软链接和default配置。
/var/www/mirror的父目录权限也要注意,Nginx worker 进程需要能读通整个路径。我一般会执行:
sudo chmod o+x /var/www sudo chmod -R a+rX /var/www/mirrorchmod -R a+rX给所有用户加读权限和进入目录的权限,同时保留可执行位只在目录上生效,这样不会给普通文件误加执行权限。
5. 内网源搭建避坑与排查:从同步中断到客户端404
5.1 同步中断后重复下载,磁盘被撑爆
现象:apt-mirror 同步到一半因为断电或者磁盘满中断,重新执行apt-mirror时发现大量包重新下载,磁盘剩余空间越来越小。
原因:同步中断后,skel目录下的索引文件和mirror目录下的实际包不同步。apt-mirror 重新运行时根据索引判断需要下载的文件,发现索引不完整就重新拉取,造成重复下载。
解决:中断后不要直接重跑同步,先执行清理脚本释放半成品文件。同时检查磁盘空间:
df -h /var/spool/apt-mirror du -sh /var/spool/apt-mirror/skel如果skel目录异常大,删掉索引重新生成,让 apt-mirror 重新拉一份干净的索引文件。我一般还会先把nthreads从 20 调到 5 再重跑,降低并发减少中断概率。
5.2 客户端访问源目录报 404
现象:内网客户端apt update时拉取http://源IP/ubuntu/dists/noble/Release返回 404,浏览器访问源 IP 首页能看到 Nginx 欢迎页,但进不到仓库目录。
原因:Nginx 的root配置没有指向软链接,或者软链接指向了不存在的目录。最常见是把root /var/www/mirror写成了root /var/www,这样请求/ubuntu/时会去/var/www/ubuntu/找,当然找不到。
解决:先在同步机上确认软链接是否有效:
ls -ld /var/www/mirror ls /var/www/mirror/ubuntu/dists/第一条看软链接有没有指向正确路径,第二条看目标目录下是否真的有仓库文件。路径没问题就回/etc/nginx/sites-enabled/default核对root行。
5.3 systemctl start nginx 失败,nginx 用户不存在
现象:离线安装完 Nginx 后执行sudo systemctl start nginx,提示Job for nginx.service failed,查看状态发现进程起不来。
原因:离线安装时 deb 包安装顺序不对,或者某些 postinst 脚本没跑成功,导致nginx用户没有创建。Nginx 主进程启动时会切换到这个用户下运行工作进程,用户缺失直接起不来。
解决:检查 nginx 用户是否存在:
id nginx如果提示用户不存在,手动创建:
sudo useradd -r -s /usr/sbin/nologin nginx-r表示创建系统用户,-s /usr/sbin/nologin禁止该用户登录,只用于服务运行。创建后再执行sudo systemctl start nginx就能正常起来。另外检查 80 端口是否被其他服务占用也很重要,ss -lntp | grep :80看一眼,有占用就先把占用进程处理掉。
5.4 客户端 apt update 报 NO_PUBKEY 或 Hash Sum mismatch
现象:内网客户端把源改成内网地址后执行sudo apt update,报错NO_PUBKEY或者Hash Sum mismatch,更新无法完成。
原因:NO_PUBKEY是客户端缺少 Ubuntu 仓库签名公钥,Hash Sum mismatch是客户端拉到的索引文件和本地已有缓存不一致,经常是同步不完整或客户端之前连着公网源拉过缓存导致的。
解决:先处理公钥:
sudo apt-key list如果确实缺 Ubuntu 签名公钥,重新安装ubuntu-keyring包:
sudo apt-get install -y --reinstall ubuntu-keyring密钥问题解决后,清理客户端缓存再更新:
sudo rm -rf /var/lib/apt/lists/* sudo apt updaterm -rf清理的是 apt 索引缓存,不会影响已安装的软件包,可以放心执行。缓存清掉后 apt 会重新拉取所有索引,Hash Sum mismatch基本都能解决。
5.5 ARM64 机器的源拉不到包
现象:内网同时有 AMD64 和 ARM64 两种架构的机器,ARM64 机器在apt update时大量 404,包拉不下来。
原因:同步机的mirror.list里没有配置 ARM64 仓库路径。apt-mirror 默认同步defaultarch amd64,只拉取了 AMD64 的包,ARM64 客户端自然找不到对应架构的 Packages 索引。
解决:在mirror.list里加一段 ARM64 的同步配置。单独建一个配置文件更清晰:
sudo vim /etc/apt/mirror-arm64.list内容基于原配置,把架构改成 arm64,仓库路径换成 ubuntu-ports:
set base_path /var/spool/apt-mirror set defaultarch arm64 set nthreads 8 deb https://mirrors.aliyun.com/ubuntu-ports noble main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu-ports noble-security main restricted universe multiverse deb https://mirrors.aliyun.com/ubuntu-ports noble-updates main restricted universe multiverse clean https://mirrors.aliyun.com/ubuntu-ports执行同步:
sudo apt-mirror /etc/apt/mirror-arm64.list同步完成后,/var/spool/apt-mirror/mirror/mirrors.aliyun.com/下会多出ubuntu-ports目录,ARM64 客户端配置源时把路径指向这个目录即可。
6. 装完怎么验证:从 apt update 到真实安装一个包
源发布完,最后一步是用客户端真实走一遍更新流程。拿一台和服务器同网段的 Ubuntu 24.04 机器,先备份原始源文件:
sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak然后编辑/etc/apt/sources.list.d/ubuntu.sources,把URIs那一行替换成内网源地址:
URIs: http://<同步机IP>/ubuntu/Suites和Components保持原来的noble noble-updates noble-backports noble-security与main restricted universe multiverse不变。改完后执行:
sudo apt update重点看输出中的状态行。正常情况会出现成片的Hit,这是索引没有变化直接命中的意思;有更新的包会显示Get。如果出现成片404,先回去查 Nginx 的 root 配置和软链接。apt update通过后,再真实装一个包验证下载链路:
sudo apt-get install -y curl装完用dpkg -l curl看版本号,确认是刚拉取的内网包,整个内网 APT 源从同步、发布到客户端使用就全部跑通了。从那以后我每次搭完源,都会强制走一遍这条验证链:清空客户端 lists 缓存、执行apt update、再真实装一个常用包,确认 Release 文件和 Packages 索引都正常才敢交付给业务方。这套流程看着多跑几分钟,实际能省掉后面一堆半夜被叫起来排查apt update报错的时间。希望帮到你。
本文还有配套的精品资源,点击获取