简介:面向企业级Linux运维与IT管理人员,提供在Ubuntu Server 24.04.1上搭建内网APT源的完整操作指南。文档覆盖环境准备、阿里云/清华镜像源选配、apt-mirror同步参数配置、Nginx发布与软链接设置,以及客户端sources.list.d更换内网IP的步骤,并针对404权限等常见问题给出排错思路,适合封闭网络下批量更新、安全合规部署场景。压缩包共1个文件,为894KB的PDF文档,可将操作流程、命令及配置样例集中查阅;已有2026人学习下载。读者可据此在无外网环境快速复现源同步与发布,减少对外部公网依赖,提升软件分发效率,同时理解内网APT源从同步、存储到对外服务的完整链路。
1. 内网 APT 源搭建:为什么偏偏要自己摆一台镜像机
某天公司网络策略收紧,新上的一批 Ubuntu Server 24.04.1 服务器只能访问内网。机器少还可以手动拷几个 deb 应急,机器一多就全卡在 apt update 上,今天缺这个包明天缺那个库,连原本十分钟能搞完的软件部署,硬生生拖成了 U 盘搬运战。最后还是要走“内网源”这条路:用 APT 同步工具把公网软件仓库拉到本地,再用 Nginx 发布到局域网,客户端改一行源地址,apt install 就跟连公网一样顺手。方案听起来不难,真正跑起来翻车点却不少——源站忘改、架构选错、同步到一半磁盘写满、Nginx 发布路径差一层目录就变成一片 404。这篇文章按一次完整落地顺序写:环境检查、apt-mirror 配置、镜像同步、Nginx 离线安装、客户端换源验证。适合统一管着几十台 Ubuntu 的运维同学,也适合第一次接触内网源搭建、想照着命令一步步走通的开发者。
2. 环境准备与安装 apt-mirror:先把架构、源站和参数敲定
2.1 确认系统版本与目标架构
搭建内网源之前,第一件事不是急着装软件,而是先想清楚“给谁用”。Ubuntu Server 24.04 的代号是 noble,apt 仓库里的发行版路径就是 noble、noble-security、noble-updates、noble-backports 这一串。只要客户端是 24.04 系列,这套源就通用,不用区分 24.04.0 还是 24.04.1。
更关键的是架构。AMD64 和 ARM64 机器在 Ubuntu 官方仓库里走的是两套不同路径:AMD64 用/ubuntu,ARM64 用/ubuntu-ports。清华 TUNA 镜像站的帮助页就是按这个维度分开列出的,很多人在这里翻车:拿着 AMD64 的源配置去同步,结果 ARM64 客户端 apt update 时永远找不到二进制包。先花一分钟确认你服务的到底是哪种架构:
lsb_release -a dpkg --print-architecture uname -mlsb_release -a看系统版本和 codename,dpkg --print-architecture看当前系统的 APT 架构,uname -m看内核架构。三行命令配合使用,基本能确定该同步哪一套仓库。实际环境中,机房往往同时存在 x86 和 ARM 两种服务器,如果都要覆盖,建议准备两台同步机或者两套独立的 base_path,分别同步 amd64 和 arm64,发布路径区分开,客户端各指各的源。
整体环境需求可以对照下面这张表:
| 项目 | 要求 | 说明 |
|---|---|---|
| 操作系统 | Ubuntu Server 24.04 / 24.04.1 noble | 客户端与同步机均可使用 |
| 架构 | AMD64、ARM64 | 两种架构仓库路径不同 |
| 下载机 | 至少一台可访问外网 | 用于 apt-mirror 同步 |
| 发布机 | Nginx 1.24.0 | 通过 HTTP 提供目录列表 |
| 客户端 | Ubuntu 24.04 系列 | 修改 /etc/apt/sources.list.d 下配置 |
2.2 下载源选型:阿里、清华、中科大怎么挑
APT 内网源搭得好不好,一大半取决于你同步的公网源稳不稳。当前 Ubuntu 24.04 主流的同步源有三个:阿里云镜像站、清华 TUNA 镜像站、中科大镜像站。阿里云在国内带宽充足,下载速度快,适合同步机带宽比较富余的场景;清华 TUNA 的优势是仓库结构完整、更新及时,而且帮助页明确区分了 ubuntu 和 ubuntu-ports,对多架构用户很友好;中科大也是老牌镜像站,网络波动时往往比前两家更稳。
我一般这样取舍:同步机在阿里云机房内,直接用阿里云源,内网访问速度快;同步机在普通机房且带宽不稳定,优先清华;中科大可以作为阿里同步失败时的备用切换源。无论选哪一家,建议从头到尾只同步同一家的仓库,不要东拼西凑。不同镜像站的 Packages 索引虽然内容等价,但同步时间点不一致,混着用可能让客户端拿到半新半旧的依赖关系。
另外注意一个容易忽略的点:内网源发布给客户端时,客户端请求路径里的主机名结构会跟着同步源变化。比如从mirrors.aliyun.com同步,镜像目录下会出现一层mirrors.aliyun.com;从mirrors.ustc.edu.cn同步,就出现一层mirrors.ustc.edu.cn。后面 Nginx 发布和客户端路径配置都依赖这层结构,一开始就把源站定下来,比中途换源省事得多。
2.3 安装 apt-mirror 同步工具
apt-mirror 是 Ubuntu 仓库里现成的同步工具,本质是一个 Perl 脚本,底层调用 wget 去拉索引和软件包。在能访问外网的下载机上直接安装:
sudo apt-get update sudo apt-get install -y apt-mirror安装完成后会自动生成/etc/apt/mirror.list配置文件。如果下载机本身也不联网,那就只能先把 apt-mirror 及其依赖的 deb 包离线拷到机器上,用 dpkg 安装,这种方式和后面 Nginx 离线安装类似,只是要多处理一层依赖。正常情况下,建议先用一台能访问外网的机器做同步,再把同步好的目录 rsync 到内网发布机,这样下载机和发布机解耦,后续扩展也更灵活。
2.4 修改 mirror.list:核心参数与镜像源地址
装完 apt-mirror 后,直接编辑配置文件:
sudo vim /etc/apt/mirror.list下面这份是我在一套 Ubuntu 24.04.1 环境中实际用过的配置,注释已经把参数含义标清楚:
############# 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 clean_script $var_path/clean.sh set defaultarch amd64 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-backports main restricted universe multiverse clean https://mirrors.aliyun.com/ubuntubase_path是镜像文件存放根目录,默认/var/spool/apt-mirror。这一步要提前确认/var所在分区是否够大,如果根分区只有二三十 GB,建议把 base_path 改到独立数据盘,比如set base_path /data/apt-mirror。nthreads 20是并发下载线程数,带宽充足可以保持,源站对单 IP 并发敏感就降到 5 到 8。
defaultarch amd64表示只同步 amd64 架构的二进制包;如果同步机本身是 ARM 架构,改成arm64。如果一套源要同时服务两种架构,我一般不用单配多架构的方案,而是建两套 base_path 分别同步,发布时用不同路径隔离,客户端配置也清晰。_tilde 0是 apt-mirror 处理文件名中波浪号的方式,保持默认即可。
deb 行是真正要镜像的仓库组件。main restricted universe multiverse四个组件基本覆盖 Ubuntu 官方全部软件包,建议都保留。noble-proposed我没放进默认配置,因为它是预发布更新通道,包质量不稳定,镜像回来后很容易影响生产环境 apt upgrade。
2.5 清掉默认源:常见误用提醒
apt-mirror 安装后,mirror.list 里自带了几行指向archive.ubuntu.com的默认 deb 配置,很多新手只把新源追加在后面,忘了删除默认源。结果同步结束后,/var/spool/apt-mirror/mirror/下同时出现archive.ubuntu.com和mirrors.aliyun.com两个目录,白白浪费带宽和磁盘。
正确的做法是打开 mirror.list 后,把所有默认 deb 行和 clean 行整体替换成目标源,不要保留原来源。另外,deb-src行除非你需要源码包,否则不要加;源码包体积大、客户端用到的场景少,同步它会让首轮同步时间几乎翻倍。
中科大源和阿里源在配置格式上完全一致,想切源只需把 URL 从https://mirrors.aliyun.com/ubuntu换成http://mirrors.ustc.edu.cn/ubuntu,codename 和组件部分不用动:
deb http://mirrors.ustc.edu.cn/ubuntu noble main restricted universe multiverse deb http://mirrors.ustc.edu.cn/ubuntu noble-security main restricted universe multiverse deb http://mirrors.ustc.edu.cn/ubuntu noble-updates main restricted universe multiverse deb http://mirrors.ustc.edu.cn/ubuntu noble-backports main restricted universe multiverse clean http://mirrors.ustc.edu.cn/ubuntu中科大的 HTTP 源不需要额外处理证书,早期网络环境里比 HTTPS 更省事。如果同步机到公网的链路一般,配置变更后先用sudo apt-mirror跑一小段,确认索引文件能正常拉取,再放它长时间同步。
3. 同步镜像源:执行 apt-mirror 与清理失效包
3.1 执行同步并观察输出
配置没问题后,直接执行同步工具:
sudo apt-mirrorapt-mirror 会先创建目录结构,然后在终端打印类似这样的过程信息:
Downloading 88 index files using 20 threads... Begin time: ... Processing indexes: [################################] ... Run /var/spool/apt-mirror/var/clean.sh for this purpose.下载索引文件的过程通常很快,后面开始拉取 pool 里的实际软件包才是真正耗时和占带宽的阶段。第一次同步 Ubuntu noble 全套组件,视网络情况可能要几个小时到十几个小时不等,建议用 tmux 或 screen 挂住,避免 SSH 断开导致同步进程跟着退出。中途断网不要慌,apt-mirror 支持增量续传,重新执行sudo apt-mirror会跳过已存在的文件,接着拉没下完的部分。
同步过程中如果刷出大量Connection reset by peer或Failed to download,先不要急着反复重启,多半是nthreads 20对源站产生了较大并发压力。把线程数降到 6 到 8 再跑,情况通常会明显好转。源站限流属于玄学范畴,不同时段表现还不一样,遇到就降线程,不要硬顶着重试。
3.2 看懂同步后的目录结构
同步完成后,镜像数据都放在 base_path 下,整体结构是这样:
/var/spool/apt-mirror/ ├── mirror/ │ └── mirrors.aliyun.com/ │ └── ubuntu/ │ ├── dists/ │ │ ├── noble/ │ │ ├── noble-security/ │ │ └── noble-updates/ │ └── pool/ ├── skel/ └── var/ ├── clean.sh └── ls-lR.gzmirror目录是实际镜像仓库的根,里面第一层是源站主机名,再往下才是ubuntu仓库路径。skel目录保存索引文件生成的中间结构,var目录存放 clean.sh 脚本和日志等运行数据。如果发现 mirror 目录下只有 archive.ubuntu.com 而没有 mirrors.aliyun.com,说明前面 mirror.list 没有清干净,立即停止继续同步,删掉不需要的源站目录,再重新执行。
有一点要在发布前就想清楚:镜像目录里多出来的mirrors.aliyun.com这层主机名,会直接影响 Nginx 发布路径和客户端 URL。我的做法是把 Nginx 根目录指到/var/www,然后在/var/www下建一个名为mirror的软链接,指向/var/spool/apt-mirror/mirror/mirrors.aliyun.com。这样客户端源地址写http://内网IP/mirror/ubuntu就能直接访问仓库,路径干净也便于以后切换源站。
3.3 清理失效包
apt-mirror 只负责把仓库拉下来,不会自动删除上游已经移除的历史包。长时间同步后,本地磁盘会被一堆已经失效的旧 deb 占满。同步结束后 apt-mirror 会提示运行清理脚本:
sudo /var/spool/apt-mirror/var/clean.shclean.sh 会读取 mirror.list 里的 clean 行和当前仓库索引,把不再属于任何发行版组件的旧包标记为过期并删除。如果发现脚本执行后没有任何反应,先检查 mirror.list 末尾是否写了对应的clean https://mirrors.aliyun.com/ubuntu;缺少 clean 行时,清理脚本可能找不到清理目标,或者报grep: ... No such file or directory之类的错误。
清理前后,建议用下面两条命令确认磁盘状态:
df -h /var/spool du -sh /var/spool/apt-mirrordf -h /var/spool看目标分区剩余空间,du -sh看镜像目录实际占用。完整同步 Ubuntu noble 四个组件,常见的占用规模在几十 GB 到一百多 GB 之间,具体取决于组件数量和更新频率。如果 mirror 目录已经占了 150GB 以上,先跑 clean.sh,再手动检查是否有历史残留,避免内网源同步到后期直接把磁盘灌满。
3.4 增量同步与定期任务
apt-mirror 的同步是增量进行的,重复执行只拉取上游新增或变化的文件,所以很适合放到定时任务里:
sudo crontab -e 0 3 * * * /usr/bin/apt-mirror > /dev/null 2>&1 30 3 * * * /var/spool/apt-mirror/var/clean.sh > /dev/null 2>&1我一般把 apt-mirror 放在凌晨带宽空闲时段,同步结束后隔半小时再跑 clean.sh,避免清理脚本和同步进程同时操作仓库目录。定期任务跑起来之后,内网源基本就是无人值守状态,只需要定期看一眼磁盘占用和日志大小。
4. Nginx 发布内网源:离线安装 1.24.0 与 autoindex 配置
4.1 离线安装 Nginx 1.24.0
内网发布机往往不能访问外网,需要准备一套完整的 Nginx deb 包,用 dpkg 离线安装。以 Ubuntu 24.04 上 Nginx 1.24.0 为例,除了主包之外,还依赖 nginx-common 和多个动态模块包,下面是实际需要准备的文件清单:
| 包名 | 架构 | 用途 |
|---|---|---|
| libgeoip1t64_1.6.12-11.1build1_amd64.deb | amd64 | GeoIP 基础库 |
| libnginx-mod-http-geoip_1.24.0-2ubuntu7.1_amd64.deb | amd64 | GeoIP 模块 |
| libnginx-mod-http-image-filter_1.24.0-2ubuntu7.1_amd64.deb | amd64 | 图片过滤模块 |
| libnginx-mod-http-xslt-filter_1.24.0-2ubuntu7.1_amd64.deb | amd64 | XSLT 过滤模块 |
| libnginx-mod-mail_1.24.0-2ubuntu7.1_amd64.deb | amd64 | 邮件代理模块 |
| libnginx-mod-stream_1.24.0-2ubuntu7.1_amd64.deb | amd64 | 流媒体模块 |
| nginx-common_1.24.0-2ubuntu7.1_all.deb | all | 公共配置文件 |
| nginx_1.24.0-2ubuntu7.1_amd64.deb | amd64 | Nginx 主程序包 |
把这些文件放进同一个目录,比如/opt/nginx-setup,然后批量安装:
sudo mkdir -p /opt/nginx-setup sudo dpkg -i /opt/nginx-setup/*.debdpkg 会按命令顺序解析依赖,如果出现dependency problems,通常是 libgeoip1t64 或 nginx-common 没有被排在前面。这时不要盲目执行apt --fix-broken install,内网机没有源可用来补装依赖,正确做法是把依赖包按顺序单独安装一遍:
sudo dpkg -i libgeoip1t64_*.deb sudo dpkg -i nginx-common_*.deb sudo dpkg -i libnginx-mod-*.deb sudo dpkg -i nginx_*.deb依赖包装完后再装主包,基本就不会报错。安装完成后先不要急着配置,确认一下服务是否能正常识别:
nginx -v如果能输出nginx version: nginx/1.24.0,说明主程序已经就位。
4.2 软链接镜像目录
假设 apt-mirror 同步好的镜像数据在/var/spool/apt-mirror/mirror/mirrors.aliyun.com,需要在 Nginx 站点根目录/var/www下建一个软链接,让 Web 访问路径能够映射到镜像目录:
sudo mkdir -p /var/www sudo ln -s /var/spool/apt-mirror/mirror/mirrors.aliyun.com /var/www/mirror sudo chown -R www-data:www-data /var/www/mirror/var/www/mirror软链接指向的是包含 ubuntu 仓库的目录,所以客户端后续访问路径是http://内网IP/mirror/ubuntu。这里的重点在于软链接只能指到mirrors.aliyun.com这一层,不能指到/var/spool/apt-mirror/mirror再往下多套一层目录,否则 Nginx 的 autoindex 列表和 apt 索引路径都会对不上。
如果下载机和发布机是两台机器,需要先把镜像目录整体拷贝或同步过去:
rsync -av --delete /var/spool/apt-mirror/mirror/ root@发布机IP:/var/spool/apt-mirror/mirror/--delete参数会让 rsync 以源端为准,删除发布机上多余文件,适合定期同步维护。第一次传输时间较长,后续增量同步就很快了。
4.3 配置 autoindex 站点并重启
发布 APT 源的核心是让 Nginx 以目录列表形式暴露仓库结构。修改默认站点配置文件:
sudo vim /etc/nginx/sites-enabled/default一个最小可用的站点配置如下:
server { listen 80 default_server; listen [::]:80 default_server; root /var/www; server_name _; autoindex on; autoindex_exact_size off; autoindex_localtime on; }root /var/www让 Nginx 站点根定位到软链接所在目录;autoindex on开启目录列表,否则访问/mirror/时 Nginx 会尝试找 index.html,找不到就返回 404。autoindex_exact_size off让目录列表显示人类可读的文件大小,autoindex_localtime on让文件时间显示为本地时区,这两项可以根据习惯保留。
如果你不想让整个/var/www都暴露成列表,可以只对/mirror/路径开启:
location /mirror/ { alias /var/www/mirror/; autoindex on; }我用的是alias而不是root,因为root会把请求路径再拼接一次,容易出现/mirror/mirror/ubuntu这种重复路径。配置完成后按顺序执行:
sudo nginx -t sudo systemctl start nginx sudo systemctl enable nginxnginx -t检查语法,没问题再启动并把服务设为开机自启。如果之前开过防火墙,还需要放行 80 端口:
sudo ufw allow 80/tcp最后在浏览器访问http://内网IP/mirror/,能看到ubuntu/目录列表,说明发布链路已经打通。这一步如果出现 403 或 404,先别改 Nginx,检查软链接指向和目录权限,大多数发布失败都出在这一层。
5. 避坑记录:我在内网源上踩过的五个坑
5.1 第一坑:同步到一半磁盘写满,wget 留下一堆空文件
现象:apt-mirror 运行大半个小时,终端开始刷No space left on device,日志里出现大量写失败的 deb 文件,重新执行同步后,apt-mirror 认为这些文件已存在,直接跳过,但实际文件是 0 字节。
原因:base_path 默认在/var/spool/apt-mirror,很多 Ubuntu 系统的/var和根分区共用,只分了 20 到 30GB。Ubuntu noble 全组件仓库体积远超这个量级,同步到一半空间耗尽。
解决:同步前先执行df -h /var/spool确认磁盘空间,不够就修改 mirror.list 里的set base_path /data/apt-mirror,把镜像目录指到独立数据盘。已经同步出来的空文件,需要删除对应路径再重新同步。从此以后,我每次搭内网源都会强制看一眼磁盘分区,绝不先跑后查。
5.2 第二坑:Nginx 服务正常,访问 /mirror/ 却 404
现象:systemctl 显示 nginx 已启动,软链接也建好了,浏览器访问http://内网IP/mirror/返回 404 Not Found,或者显示 403 Forbidden。
原因:Ubuntu 自带的 nginx 默认站点 root 指向/var/www/html,软链接却建在/var/www下,Nginx 根本不会去那里找文件。另一个原因是 autoindex 没开启,Nginx 找不到 index.html 就直接返回 404。
解决:修改/etc/nginx/sites-enabled/default,把root /var/www写入配置,并加上autoindex on。同时确认软链接的父目录权限可读,www-data用户能穿越到镜像目录。每次改完配置都要执行sudo nginx -t && sudo systemctl restart nginx,让配置真正生效。
5.3 第三坑:客户端 apt update 报证书验证失败
现象:客户端已经把源地址写进了/etc/apt/sources.list.d/ubuntu.sources,但执行 apt update 时提示Certificate verification failed: The certificate is NOT trusted,更新流程直接中断。
原因:内网发布走的是 HTTP,客户端配置里却把 URIs 写成了https://,或者旧配置文件里的官方 HTTPS 地址只替换了 IP 没有替换协议。内网 IP 没有合法证书,HTTPS 握手自然失败。
解决:统一把客户端 URIs 写成http://内网IP/mirror/ubuntu,不要用 https。如果内网环境有安全要求必须做 TLS,就自建 CA 并给 APT 客户端配置对应的证书信任链,不要通过[trusted=yes]绕过,那会让整个仓库失去签名校验。
5.4 第四坑:mirror.list 没改干净,把官方源同步回来了
现象:同步完成后,/var/spool/apt-mirror/mirror/下出现archive.ubuntu.com、security.ubuntu.com等目录,而自己想要的mirrors.aliyun.com目录反而不完整。
原因:apt-mirror 安装时自动生成的 mirror.list 自带官方源的 deb 行,执行者只追加了新源,没有删掉默认源。apt-mirror 会忠实地把所有 deb 行都同步一遍。
解决:修改 mirror.list 时直接把默认 deb 行和 clean 行整体替换为目标源,不保留任何 archive.ubuntu.com 相关配置。已经同步出来的多余目录,确认无用后清理掉。这个坑非常隐蔽,尤其是从网上复制配置片段时,一不留神就把新旧源混在一起。
5.5 第五坑:nthreads 调太高,源站频繁 reset 连接
现象:apt-mirror 日志反复出现Connection reset by peer,下载进度长时间不动,重启后仍然从失败点继续报错。
原因:源站对单 IP 并发连接有限流,nthreads 20在某些时段触发了源站保护机制,导致连接被重置。
解决:把 mirror.list 里的set nthreads降到 6 到 8,重新执行 apt-mirror。源站限流是动态策略,早晚高峰表现不一样,不用反复重试同一个高并发配置。同步机带宽较小的情况下,还要接受下载速度不如预期的现实,慢慢拉总比频繁断流强。
6. 验证跑通:客户端换源,三步走完给你看
6.1 修改客户端的 ubuntu.sources
Ubuntu 24.04 默认使用 deb822 格式的源文件,路径是/etc/apt/sources.list.d/ubuntu.sources,不是以前惯用的/etc/apt/sources.list。这是很多人验证时找不到配置位置的原因。备份原文件后直接编辑:
sudo cp /etc/apt/sources.list.d/ubuntu.sources /etc/apt/sources.list.d/ubuntu.sources.bak sudo vim /etc/apt/sources.list.d/ubuntu.sources把 URIs 改成内网 Nginx 发布地址,一个完整可用的配置如下:
Types: deb URIs: http://192.168.1.10/mirror/ubuntu Suites: noble noble-updates noble-backports noble-security Components: main restricted universe multiverse Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg如果客户端还是老式单行 sources.list 格式,就写成:
deb [ trusted=yes ] http://192.168.1.10/mirror/ubuntu noble main restricted universe multiverse内网源推荐用 HTTP,能避免证书问题。trusted=yes只在内网测试环境用来救急,生产环境不要长期使用,否则仓库签名校验形同虚设。
6.2 验证三连:update、apt-cache、实际安装
客户端换源后,按顺序执行三条命令验证:
sudo apt update看到Get:1 http://192.168.1.10/mirror/ubuntu noble InRelease这类输出,说明客户端已经能连上内网源。如果这里报错,优先检查 IP 是否可达、Nginx 路径是否多了一层目录。
然后确认包索引已经能用内网源解析:
apt-cache policy nginx输出里会出现Candidate版本号,说明 apt 已经从内网源拿到了 nginx 包信息。最后做一次真实安装测试,选一个常见软件包:
sudo apt install -y curl安装过程如果不再访问公网域名,而是从内网 IP 下载 deb,说明整条链路已经完全跑通。我之前习惯只跑到 apt update 就认为大功告成,后来发现 update 成功不代表包能正常下载,目录权限或者软链接层级错误可能到 install 阶段才暴露。从那以后,我每次搭完一套内网源都会强制走一遍“更新索引、查询包、实际安装”三连确认,三步全过才敢交付给同事用,免得第二天一堆服务器的更新全挂在同一处 404 上。希望这篇安装笔记能帮到你,把该踩的坑先替你踩平。
本文还有配套的精品资源,点击获取