Rocky9.2局域网yum源搭建:http方式与reposync同步实战 简介这份文档面向需要在隔离内网中批量部署与维护 Rocky Linux 服务器的运维人员针对无法访问互联网、逐台配置本地源或手动安装 rpm 包效率低下的痛点给出基于 HTTP 搭建局域网 YUM 源的完整方案。资源包共 1 个 docx 文件约 120KB以图文步骤形式记录从镜像挂载、仓库配置到客户机验证的全过程便于按章节查阅与落地复现。内容以 Rocky Linux 9.2 为例覆盖 YUM 服务器与客户机双机环境准备、BaseOS 与 AppStream 仓库定义、httpd 服务部署与防火墙及 SELinux 策略调整、客户机 baseurl 指向服务器 IP 后的缓存清理与验证等关键环节并附有可直接参考的配置片段与命令示例。目前已有 1693 人学习适合希望提升内网软件部署效率、保障版本一致性的 Linux 运维与系统管理员参考。1. Rocky9.2 局域网 yum 源为什么 http 方式比你想的更值得折腾机房里有二十台 Rocky9.2 的机器外网出口只有一条每次dnf install都排队等带宽装一台数据库节点能卡半小时。这种场景下把一台机器做成局域网 yum 源其余机器从内网拉包是最省事的解法。而 http 方式相比 nfs、ftp配置最简单、客户端零额外依赖dnf原生就认http://开头的 baseurl不用装任何插件。这篇讲的就是在一台 Rocky9.2 上把官方仓库和常用第三方仓库同步到本地用 httpd 暴露出去让整个局域网的其他 Rocky9.2 机器改一个 repo 文件就能用。适合手里有内网集群、离线环境、或者单纯想省外网流量的运维和开发。下面从选型、同步、发布、客户端配置一路写到排错参数和坑都给全。2. 先想清楚同步哪些仓库、放哪、怎么暴露2.1 仓库选型BaseOS、AppStream 和 EPEL 的取舍Rocky9.2 的官方仓库主要就两个BaseOS放内核、基础库这类系统级包AppStream放应用流、开发工具、语言运行时。这两个是必同步的缺了dnf groupinstall会直接报找不到组。EPEL 是第三方补充仓库很多常用工具比如htop、nginx的部分依赖在里面要不要同步看你的业务。同步策略上有个关键判断全量同步还是按需同步。全量同步 BaseOS AppStream 大概 1520 GBEPEL 再加几个 GB。如果内网机器多、装的软件杂全量最省心一次同步长期受益。如果只是固定几台机器跑固定服务可以只同步需要的包但维护成本高不推荐新手这么干。我一般会同步三个仓库BaseOS、AppStream、EPEL。前两个保证系统能正常装软件EPEL 覆盖常见工具。同步工具用reposync它属于dnf-plugins-core包Rocky9.2 默认可能没装。# 安装同步和建索引需要的工具 dnf install -y dnf-plugins-core createrepo_c httpd # 确认仓库已启用能看到 repo id dnf repolist enableddnf-plugins-core提供reposync和dnf config-managercreaterepo_c是 C 版本的重写比老的createrepo快很多Rocky9 上默认就是它。httpd就是后面用来暴露目录的 web 服务。执行完dnf repolist enabled应该能看到baseos、appstream、extras这些 repo id记下来同步时要用。2.2 目录规划别把仓库塞进根分区同步目录的规划是个容易被忽略但很要命的点。默认reposync会往当前目录下的子目录写如果你在/root下执行20 GB 数据全进根分区根分区一满系统直接出问题。血泪经验单独挂一块盘或者至少指到一个大分区。我习惯的布局是这样路径用途建议容量/data/yum/rocky/9.2/BaseOS/x86_64BaseOS 仓库810 GB/data/yum/rocky/9.2/AppStream/x86_64AppStream 仓库1012 GB/data/yum/epel/9/Everything/x86_64EPEL 仓库58 GB/var/www/html/repohttpd 暴露的软链或挂载点指向 /data/yum/data单独一块盘/var/www/html/repo用软链接指过去这样 httpd 的 DocumentRoot 不用改权限也好控制。注意 SELinux 在 Rocky9.2 默认是 enforcing软链接跨目录访问会被拦后面排错章节会专门讲这个。# 建目录结构 mkdir -p /data/yum/rocky/9.2/{BaseOS,AppStream}/x86_64 mkdir -p /data/yum/epel/9/Everything/x86_64 # 建 httpd 暴露点用软链指向数据盘 mkdir -p /var/www/html/repo ln -s /data/yum /var/www/html/repo/yum # 确认软链生效 ls -l /var/www/html/repo/mkdir -p的-p保证父目录不存在时一起建。软链这一步是关键/var/www/html/repo/yum最终指向/data/yum客户端访问http://服务器IP/repo/yum/...就能拿到包。执行完ls -l应该看到yum - /data/yum这样的输出。如果 SELinux 开着这个软链访问会失败先记着第 5 章解决。3. 同步仓库并生成 repodatareposync 与 createrepo_c 实操3.1 用 reposync 把远程仓库拉到本地reposync的核心参数就几个但每个都影响结果。-p指定下载根目录-r指定 repo id--download-metadata让它在下载包的同时把远程的 repodata 也拉下来这样后面createrepo_c可以增量更新速度快很多。不加这个参数每次都要全量重建索引几万个包能跑很久。# 同步 BaseOS-n 表示只下载最新的包不保留旧版本 reposync -p /data/yum/rocky/9.2/BaseOS/x86_64 \ -r baseos \ --download-metadata \ -n # 同步 AppStream reposync -p /data/yum/rocky/9.2/AppStream/x86_64 \ -r appstream \ --download-metadata \ -n # 同步 EPEL前提是已装 epel-release dnf install -y epel-release reposync -p /data/yum/epel/9/Everything/x86_64 \ -r epel \ --download-metadata \ -n-n是--newest-only只拉每个包的最新版本。局域网源一般不需要历史版本加上它能省不少空间。如果你有回滚需求去掉-n但空间会翻倍。--download-metadata是 Rocky9 上reposync比较新的行为老版本 CentOS 的reposync没这个参数别照搬老教程。同步时间取决于带宽BaseOS 全量大概 8000 多个包百兆外网跑一两个小时正常。建议挂screen或tmux里跑别在 ssh 会话里直接跑断线就前功尽弃。提示第一次同步前先df -h确认目标分区剩余空间BaseOS AppStream EPEL 全量预留 30 GB 比较稳妥。3.2 createrepo_c 生成索引与增量更新包下载完目录里只有一堆 rpm 和从远程带下来的 repodata。要让dnf能识别必须生成本地 repodata。createrepo_c的--update参数是增量更新的关键如果目录里已有 repodata它只处理新增和变化的包不重建全部。# 为 BaseOS 生成索引--update 支持增量 createrepo_c --update /data/yum/rocky/9.2/BaseOS/x86_64 # AppStream 和 EPEL 同理 createrepo_c --update /data/yum/rocky/9.2/AppStream/x86_64 createrepo_c --update /data/yum/epel/9/Everything/x86_64执行完每个目录下会多出repodata/文件夹里面有repomd.xml和一堆压缩的索引文件。repomd.xml是客户端第一个请求的文件它记录了其他索引文件的校验和。如果这个文件损坏或时间戳不对客户端会报Cannot download repomd.xml或者校验失败。增量更新的正确姿势是先reposync拉新包再createrepo_c --update。不要反过来也不要在reposync没跑完就执行createrepo_c否则索引和实际包对不上客户端装包时报 404。这个顺序坑我踩过索引里有个包但文件没下完dnf install直接卡住。3.3 用 httpd 把仓库暴露到局域网httpd 的配置很简单但有两个点必须确认一是DocumentRoot下的软链要能被跟随二是 SELinux 上下文要对。先改 httpd 配置允许跟随软链。# 编辑 httpd 配置在 Directory /var/www/html 段里加 FollowSymLinks cat /etc/httpd/conf.d/yum-repo.conf EOF Directory /var/www/html/repo Options Indexes FollowSymLinks AllowOverride None Require all granted /Directory EOF # 启动并设开机自启 systemctl enable --now httpd # 本机验证能否访问 curl -I http://127.0.0.1/repo/yum/rocky/9.2/BaseOS/x86_64/repodata/repomd.xmlOptions Indexes FollowSymLinks里Indexes允许目录列表方便浏览器直接看FollowSymLinks允许跟随软链缺了它访问软链会 403。Require all granted是 httpd 2.4 的语法老教程里的Order allow,deny在 Rocky9 上不生效。curl -I只取响应头看到HTTP/1.1 200 OK就说明 httpd 能正常读到文件。如果返回 403八成是 SELinux 拦了软链或者文件权限不对。如果返回 404检查软链路径和 URL 是否对得上。这一步过了服务端就算搭完了。4. 客户端接入repo 文件怎么写、缓存怎么清4.1 客户端 repo 文件的最小写法客户端这边要做的就一件事把/etc/yum.repos.d/下的官方 repo 文件挪走或禁用换成指向内网源的。最干净的做法是新建一个lan.repo把官方文件备份后删掉避免两个源同时生效导致混乱。# /etc/yum.repos.d/lan.repo [lan-baseos] nameLAN Rocky9.2 BaseOS baseurlhttp://192.168.1.100/repo/yum/rocky/9.2/BaseOS/x86_64 enabled1 gpgcheck0 [lan-appstream] nameLAN Rocky9.2 AppStream baseurlhttp://192.168.1.100/repo/yum/rocky/9.2/AppStream/x86_64 enabled1 gpgcheck0 [lan-epel] nameLAN EPEL9 baseurlhttp://192.168.1.100/repo/yum/epel/9/Everything/x86_64 enabled1 gpgcheck0baseurl里的 IP 换成你服务端的实际地址。gpgcheck0是内网源的常见做法因为本地 repodata 的签名校验在局域网里意义不大而且开了还要把 GPG key 也同步过去麻烦。如果你有合规要求必须校验把gpgcheck1并配gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9前提是客户端有这个 key 文件。enabled1表示启用name随便写但建议写清楚dnf repolist时会显示。三个仓库的 repo id 不要重复否则dnf会报冲突。4.2 清缓存、验证、装包一条龙改完 repo 文件必须清缓存否则dnf还用旧的元数据。清缓存有两个层级clean metadata清元数据clean all连包缓存一起清。换源后建议clean all再makecache。# 备份并移除官方 repo 文件避免干扰 mkdir -p /etc/yum.repos.d/bak mv /etc/yum.repos.d/rocky*.repo /etc/yum.repos.d/bak/ 2/dev/null # 清所有缓存 dnf clean all # 重建缓存这一步会从内网源拉 repodata dnf makecache # 确认仓库列表 dnf repolist # 装个包验证 dnf install -y htopdnf makecache会下载所有启用仓库的元数据并缓存到/var/cache/dnf/如果这一步报Failed to download metadata for repo说明客户端连不上服务端或者 URL 写错了。dnf repolist应该只显示lan-baseos、lan-appstream、lan-epel三个如果还混着官方源说明备份没干净。dnf install -y htop是最终验证能装上就说明整条链路通了。装的时候观察下载速度内网千兆环境下应该几秒就完事如果还是慢检查是不是走了外网。注意如果客户端和服务端之间有防火墙确认 80 端口放行。firewall-cmd --add-servicehttp --permanent firewall-cmd --reload在服务端执行一次。5. 避坑与排查SELinux、权限、缓存不一致的五个真实翻车5.1 现象客户端 403 Forbiddenhttpd 日志报 permission denied原因Rocky9.2 默认 SELinux enforcing/var/www/html/repo/yum这个软链指向/data/yum而/data/yum的 SELinux 上下文是default_thttpd 进程没有权限读。httpd 只能读httpd_sys_content_t类型的文件。解决给数据目录打上正确的上下文标签并让标签持久化。# 递归打标签 semanage fcontext -a -t httpd_sys_content_t /data/yum(/.*)? restorecon -Rv /data/yum # 确认标签 ls -Z /data/yum/rocky/9.2/BaseOS/x86_64/repodata/repomd.xmlsemanage来自policycoreutils-python-utils包没装先dnf install -y policycoreutils-python-utils。restorecon -Rv按规则重新打标签-R递归-v显示过程。执行完ls -Z应该看到httpd_sys_content_t。这一步不做软链方案在 SELinux 下必挂。5.2 现象dnf makecache 报 repomd.xml 校验失败原因createrepo_c生成索引后又手动往目录里拷了 rpm或者reposync没跑完就建了索引导致 repodata 里记录的包和实际文件对不上。解决重新跑一次createrepo_c --update让它扫描实际文件重建索引。如果还不行删掉repodata目录全量重建。# 全量重建先删旧索引 rm -rf /data/yum/rocky/9.2/BaseOS/x86_64/repodata createrepo_c /data/yum/rocky/9.2/BaseOS/x86_64全量重建比增量慢但能保证一致性。日常维护记住顺序先同步包再建索引中间不要手动动文件。5.3 现象客户端装包报 404但浏览器能打开目录原因客户端缓存了旧的 repodata里面记录的包路径和服务端实际路径不一致。常见于服务端重新同步后客户端没清缓存。解决客户端dnf clean all dnf makecache。如果还不行检查服务端repomd.xml的修改时间确认客户端拉的是最新的。5.4 现象reposync 跑到一半断了重跑报文件已存在原因reposync默认不覆盖已存在的文件断点续传行为依赖具体版本。中断后残留的临时文件会让重跑卡住。解决加--delete让 reposync 清理目标目录里不在远程仓库的文件或者手动删掉.tmp残留。更稳的做法是重跑前先确认没有reposync进程残留。# 确认没有残留进程 ps aux | grep reposync # 重跑时加 --delete 清理孤儿文件 reposync -p /data/yum/rocky/9.2/BaseOS/x86_64 -r baseos --download-metadata -n --delete--delete会删掉本地有但远程没有的包适合仓库结构变化后重新对齐。但如果你本地手动加过包慎用。5.5 现象内网机器 dnf 还是走外网速度没变原因官方 repo 文件没删干净或者lan.repo里enabled0或者dnf的--disablerepo全局配置还在。解决dnf repolist --all看所有仓库状态确认官方源是 disabled。检查/etc/dnf/dnf.conf里有没有exclude或disablerepo之类的全局配置。最彻底的办法是把/etc/yum.repos.d/下非lan.repo的文件全挪走。6. 进阶用 rsync 增量同步 定时任务把维护成本压到最低第一次全量同步之后日常维护其实只需要增量更新。reposync每次都会去远程比对但全量扫描几万个包的元数据也要几分钟。更高效的做法是用rsync直接同步远程镜像站配合createrepo_c --update只处理变化的包。先找一个稳定的上游镜像站用rsync拉取。Rocky 官方和国内几个镜像站都提供 rsync 服务具体地址按你网络环境选。同步脚本大概长这样#!/bin/bash # /usr/local/bin/sync-yum-repo.sh set -e UPSTREAMrsync://mirror.example.com/rocky/9.2 LOCAL/data/yum/rocky/9.2 # 增量同步 BaseOS 和 AppStream--delete 保持与上游一致 rsync -av --delete \ --excluderepodata/ \ ${UPSTREAM}/BaseOS/x86_64/ \ ${LOCAL}/BaseOS/x86_64/ rsync -av --delete \ --excluderepodata/ \ ${UPSTREAM}/AppStream/x86_64/ \ ${LOCAL}/AppStream/x86_64/ # 重建索引--update 增量 createrepo_c --update ${LOCAL}/BaseOS/x86_64 createrepo_c --update ${LOCAL}/AppStream/x86_64 # 记录同步时间方便排查 date /var/log/yum-sync.log echo sync done /var/log/yum-sync.log--excluderepodata/是关键上游的 repodata 是给外网客户端用的路径和校验方式跟本地不一定兼容排除掉自己用createrepo_c生成更可靠。--delete保证本地和上游一致上游删掉的旧包本地也删避免索引里有过期条目。把这个脚本挂到 cron 里每天凌晨跑一次# 每天 3 点同步 echo 0 3 * * * /usr/local/bin/sync-yum-repo.sh | crontab -验证同步是否正常看两个地方一是/var/log/yum-sync.log有没有当天的记录二是客户端dnf makecache后dnf list available能不能看到新包。如果 rsync 报错先手动跑一次看具体哪个文件失败常见的是上游镜像站临时不可用或者磁盘满。一个我自己的习惯每次改完同步脚本先在测试机上跑一遍rsync --dry-run看它打算删哪些文件。--delete用错方向能把整个仓库清空这个后悔药可不好买。另外createrepo_c --update在包数量变化大时偶尔会留下旧索引条目每隔一两个月做一次全量createrepo_c不加--update能清掉这些残留。这套方案跑顺了内网几十台机器的 yum 维护基本不用管希望帮到你。本文还有配套的精品资源点击获取