内网APT源搭建:apt-mirror同步与Nginx发布完整指南
发布时间:2026/10/23 15:05:28 锦皓数字建站

简介面向企业级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 的代号是 nobleapt 仓库里的发行版路径就是 noble、noble-security、noble-updates、noble-backports 这一串。只要客户端是 24.04 系列这套源就通用不用区分 24.04.0 还是 24.04.1。更关键的是架构。AMD64 和 ARM64 机器在 Ubuntu 官方仓库里走的是两套不同路径AMD64 用/ubuntuARM64 用/ubuntu-ports。清华 TUNA 镜像站的帮助页就是按这个维度分开列出的很多人在这里翻车拿着 AMD64 的源配置去同步结果 ARM64 客户端 apt update 时永远找不到二进制包。先花一分钟确认你服务的到底是哪种架构lsb_release -a dpkg --print-architecture uname -mlsb_release -a看系统版本和 codenamedpkg --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/ubuntucodename 和组件部分不用动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 21 30 3 * * * /var/spool/apt-mirror/var/clean.sh /dev/null 21我一般把 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.debamd64GeoIP 基础库libnginx-mod-http-geoip_1.24.0-2ubuntu7.1_amd64.debamd64GeoIP 模块libnginx-mod-http-image-filter_1.24.0-2ubuntu7.1_amd64.debamd64图片过滤模块libnginx-mod-http-xslt-filter_1.24.0-2ubuntu7.1_amd64.debamd64XSLT 过滤模块libnginx-mod-mail_1.24.0-2ubuntu7.1_amd64.debamd64邮件代理模块libnginx-mod-stream_1.24.0-2ubuntu7.1_amd64.debamd64流媒体模块nginx-common_1.24.0-2ubuntu7.1_all.deball公共配置文件nginx_1.24.0-2ubuntu7.1_amd64.debamd64Nginx 主程序包把这些文件放进同一个目录比如/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 客户端配置对应的证书信任链不要通过[trustedyes]绕过那会让整个仓库失去签名校验。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.sourcesUbuntu 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 [ trustedyes ] http://192.168.1.10/mirror/ubuntu noble main restricted universe multiverse内网源推荐用 HTTP能避免证书问题。trustedyes只在内网测试环境用来救急生产环境不要长期使用否则仓库签名校验形同虚设。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 上。希望这篇安装笔记能帮到你把该踩的坑先替你踩平。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。