HTTP协议在局域网自建Rocky9.2 yum源:repodata到客户端接入

发布时间:2026/9/30 10:44:47
HTTP协议在局域网自建Rocky9.2 yum源:repodata到客户端接入 简介给内网环境运维人员的一份Rocky Linux 9.2基于HTTP搭建局域网YUM源实操文档解决无法访问互联网时批量安装与更新软件依赖的问题。资源为docx格式共1个文件压缩包仅120KB便于快速下载查阅。文档完整覆盖环境准备、镜像挂载、本地源配置、httpd部署、客户端baseurl修改及缓存刷新等步骤配有可直接复用的配置示例和验证命令适合需要为多台同版本Linux服务器统一提供软件源的运维工程师。已有1691人学习该方法具备通用性可迁移至其他基于RPM的发行版具有较强工程实践价值。1. 什么场景会让你想用http在局域网自建一个Rocky9.2的yum源机房里有十几台Rocky9.2的机器装完就断外网每次装软件都得往U盘里拷rpm包拷进去还面临依赖缺失那叫一个憋屈。我用http协议在局域网里搭了一个yum源让所有机器只要写一个repo文件就能按需拉取任何依赖先说结论这是内网软件分发里投入产出比最高的一种做法。这篇不讲虚的从服务器端的目录规划、repodata元数据到客户端的repo配置和排错是一套能直接照做的完整方案。适合给实验室、机房、离线生产网维护基础软件源的人也适合想把yum源内部逻辑一次搞懂的Linux运维初学者。2. 先想清楚三件事为什么是http、源目录是什么、repodata是什么很多人把自建yum源想复杂了。它本质上就三块一台能通过http协议访问到文件的服务器、一个按仓库结构组织好的rpm包目录、一份让dnf能读懂目录的repodata元数据。这三块搞明白后面搭起来就是执行命令的事。2.1 Rocky9.2的源目录里到底放着什么Rocky9.2延续了RHEL9的仓库拆分方式最基本的两个仓库是BaseOS和AppStream。BaseOS里是操作系统基础运行时的包类似kernel、glibc、systemd这些AppStream里是开发工具、运行时环境和附加软件比如nginx、php、postgresql。官方ISO的根目录下就能看到这两个目录且各自带着一份repodata。AppStream和BaseOS还有一个关键区别AppStream里带着模块化元数据在Rocky9.2的ISO里对应文件名是modules.yaml.gz。这套数据负责描述“同一软件有哪些版本流可选”比如php有几个大版本、postgresql有几个系列。后面客户端执行dnf module list nginx想看模块时靠的就是这份文件。很多教程只让人拷贝rpm包把modules.yaml.gz漏了等发现模块列表查不到时已经晚了。网上还有不少旧教程会把“本地yum源”简化成一个目录挂载点加createrepo。这种做法在Rocky9上不一定成立因为你手上通常不是一堆散包而是一份已经带repodata的官方目录。直接从ISO拷贝或从可信镜像同步时这份repodata要原样保留不要手贱重新生成否则模块信息可能被抹掉。2.2 http、file、nfs三种暴露方式怎么选yum/dnf支持的源协议不止http。常见有三种file、nfs、http。很多人在选型上纠结我的结论很直接如果目标是给局域网多台机器用优先http。方式客户端要求典型坑适合场景file无但仅限本机或共享存储远端机器没法直接指file://到另一台机器的路径单机离线维护nfs需要安装nfs-utils并处理挂载root_squash、exports权限、防火墙排查链路长少量受控机器、特殊共享需求http无额外依赖防火墙放行80端口即可局域网批量主机、长期维护为什么是http而不是https这里说清楚http和https的差别核心在于加密和证书信任。局域网内部没有公网中间人风险而rpm包本身自带GPG签名dnf在安装前会做包完整性校验。再加一层自签https证书反而要处理客户端的证书信任问题属于自己给自己加工作量。我在生产环境里见过因为自签证书过期导致整个源不可用的案例这种坑完全没必要踩。http还有一个运维上的隐形红利调试方便。客户端连不上时curl一下URL就能定位服务端有access_log谁在什么时候拉过哪些包一目了然如果以后机器多了前面加个负载均衡也行。nfs和file都没有这种对排障友好的可观测性。2.3 repodata一个源能不能被dnf使用的黑匣子一个目录里有再多的rpm包如果没有repodatadnf也无法直接使用。repodata是dnf消费仓库的入口它下面最常见的是repomd.xml、primary.xml.gz、filelists.xml.gz、other.xml.gz这几个文件。dnf访问一个仓库时首先请求的就是repodata/repomd.xml。repomd.xml里记录了当前仓库里其他元数据文件的位置、校验和、时间戳。dnf拿到primary.xml.gz后才能知道这个仓库有哪些包、每个包的版本、依赖关系和provides信息filelists负责提供文件路径查询解决“某个命令在哪个包里”的问题other则记录changelog等次要信息。所以自建源的“源数据”分两种情况如果你是从官方ISO或可信镜像同步过来的目录repodata是现成的哪怕你看不到那些.xml.gz文件只要repodata目录存在就行如果你手里真的只有一堆散装rpm包没有任何元数据那就得用createrepo_c生成一份命令在第3章里给。3. 服务端搭建挂载ISO、装httpd、把Rocky9.2仓库暴露给局域网这一章从零开始假设服务端是一台刚装好的Rocky9.2机器也许这台机器本身也还没有可用yum源。我一般从ISO先把httpd和createrepo_c装出来再把仓库内容同步到/var/www/html下全程用命令验证。3.1 准备Rocky9.2 DVD介质并挂载先准备一份Rocky-9.2-x86_64-dvd.iso放到服务器本地路径然后挂载到固定挂载点。没有DVD没关系同样可以使用U盘或其他可用的安装介质但ISO最省事。mkdir -p /media/rocky92 mount -o loop,ro /path/to/Rocky-9.2-x86_64-dvd.iso /media/rocky92 ls /media/rocky92挂载后应能看到BaseOS和AppStream两个目录。注意mount命令里-o loop,ro表示以只读方式挂载镜像文件/path/to/是ISO文件的实际路径按你自己的情况改。ISO本身是只读的不能直接往里加包所以后续要把它拷贝到硬盘目录而不是把挂载点直接当作源。临时看一眼可以长期用不行。如果这台服务端连yum源都没有我还会顺手在这个阶段配置一个临时DVD源让后面的dnf命令能从ISO里装软件避免“装httpd也需要先有yum源”的死循环。[rocky-dvd-BaseOS] nameRocky9.2 DVD BaseOS baseurlfile:///media/rocky92/BaseOS enabled1 gpgcheck0 [rocky-dvd-AppStream] nameRocky9.2 DVD AppStream baseurlfile:///media/rocky92/AppStream enabled1 gpgcheck0把这个临时repo文件放到/etc/yum.repos.d/下例如命名dvd-local.repo然后执行dnf list available httpd能查到即可。这里gpgcheck0只是针对本机临时的DVD源后续局域网源要不要开gpgcheck第4章会专门讲。3.2 用DVD源安装httpd和createrepo_c临时DVD源就绪后安装工具就一句话的事。dnf install -y httpd createrepo_c systemctl enable --now httpdcreaterepo_c是createrepo的C语言实现版本Rocky9默认仓库里提供的就是它处理大量rpm时速度更快。httpd装好后默认的DocumentRoot就是/var/www/html所以把源目录规划在/var/www/html/yum下面不需要改httpd.conf。这样做的额外好处是SELinux对/var/www/html有默认的httpd_sys_content_t类型不会出现权限拦路。如果服务端有firewalld在运行需要放行http服务否则客户端访问会被拒。firewall-cmd --permanent --add-servicehttp firewall-cmd --reload3.3 把Rocky9.2仓库内容同步到/var/www/html现在把ISO里的BaseOS和AppStream内容同步到httpd的发布目录。我用rsync而不是cp原因很简单rsync支持断点续传、可以增量同步以后镜像源更新时只需要重跑一遍rsync。mkdir -p /var/www/html/yum/9.2 rsync -av /media/rocky92/BaseOS/ /var/www/html/yum/9.2/BaseOS/ rsync -av /media/rocky92/AppStream/ /var/www/html/yum/9.2/AppStream/注意两个细节第一源路径都以/结尾代表同步目录内容而不是目录本身第二rsync只用了-av没有用-X也就是说不会把ISO文件系统上奇怪的SELinux上下文带到目标目录文件会按/var/www/html的默认上下文创建这一步其实能避开一个不小的坑。同步完成后务必检查目标目录里有没有repodatals /var/www/html/yum/9.2/BaseOS/repodata/repomd.xml ls /var/www/html/yum/9.2/AppStream/repodata/repomd.xml如果你手头只有散装rpm目录而没有repodata才需要手动生成。BaseOS直接生成createrepo_c /var/www/html/yum/9.2/BaseOSAppStream则要带上modules.yaml.gz否则模块信息会丢cd /var/www/html/yum/9.2/AppStream createrepo_c --modules modules.yaml.gz .--modules参数让createrepo_c把modules.yaml.gz里的模块元数据并进新生成的repodata。这里的.表示当前目录前提是先进入AppStream根目录且modules.yaml.gz就在那里。我见过有人把rpm拷到另一个目录后重新createrepo因为没带这个参数导致后面dnf module list一片空白属于特定于Rocky9/RHEL9的高发坑。3.4 验证服务端整条链路源目录就绪后先用curl在服务端本机验一遍httpd是否正常返回repomd.xml。curl -I http://127.0.0.1/yum/9.2/BaseOS/repodata/repomd.xml curl -I http://127.0.0.1/yum/9.2/AppStream/repodata/repomd.xml两个URL都应返回200 OK。如果返回404先确认路径大小写BaseOS里的B和AppStream里的S都是大写字母大小写搞错是最常见的低级错误。如果返回403多半是SELinux或目录权限问题第5章里有专门记录。最后再验证一下repomd.xml内容能被正常解析取前几行看一眼即可curl -s http://127.0.0.1/yum/9.2/BaseOS/repodata/repomd.xml | head -n 8看到repomd和revision标签服务端就算全部完成。可以拿另一台局域网机器curl http://192.168.1.10/yum/9.2/BaseOS/repodata/repomd.xml再验一次确认不是只有本机能访问。4. 客户端接入写repo文件、关官方源、验证yum源可用服务端只是前半程客户端无非是“关掉出网试探指向内网地址”。最影响体验的问题往往是客户端还保留着官方源dnf先去访问外网mirrorlist超时后才轮到本地源整个过程慢到像卡死。4.1 先禁用官方repo避免内网机器无谓地出网试探Rocky9.2安装后/etc/yum.repos.d/下默认有Rocky-BaseOS.repo、Rocky-AppStream.repo这些文件。如果这些机器本来就不该出外网官方源留着只会拖慢每次dnf操作。mkdir -p /etc/yum.repos.d/bak mv /etc/yum.repos.d/Rocky-*.repo /etc/yum.repos.d/bak/官方源被移走后dnf就只剩你手写的本地源配置。这里不建议用enabled0逐个注释批量改名最干净以后想恢复时再mv回去即可。4.2 写一个指向内网的rocky-local.repo在客户端/etc/yum.repos.d/下新建一个rocky-local.repo内容如下其中192.168.1.10改成你的服务端实际IP[rocky-BaseOS] nameRocky 9.2 BaseOS baseurlhttp://192.168.1.10/yum/9.2/BaseOS/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 metadata_expire1d [rocky-AppStream] nameRocky 9.2 AppStream baseurlhttp://192.168.1.10/yum/9.2/AppStream/ enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9 metadata_expire1d两个仓库要分开写不能合并成一个baseurl指向9.2根目录因为dnf会把目录当作一个仓库去抓repodata而根目录下没有repomd.xml。gpgcheck这里保留1gpgkey指向客户端本机的Rocky官方GPG公钥Rocky9.2最小化安装一般自带这个文件。如果客户端找不到这个key文件可以从服务端拷一份到相同路径或者把gpgcheck改成0代价是放弃对rpm包的GPG签名校验。metadata_expire是我特别强调的参数。默认情况下dnf会按发行版给的策略缓存元数据可能几小时就过期。自建源内容基本是静态的我习惯改成1d减少客户端频繁重新拉取repodata。万一服务端真的更新了包可以让客户端执行dnf clean all强制刷新这个操作比调低过期时间可控得多。4.3 用dnf makecache和repolist验证配置是否生效配置好repo文件后依次执行下面三条命令这是从零确认一个yum源能不能用的标准动作dnf clean all dnf makecache dnf repolistdnf clean all清掉客户端本地所有缓存和元数据dnf makecache让dnf从baseurl重新拉取repodatadnf repolist就是平时说的“查看yum源”列出当前已启用的仓库及rpm包数量。到这里如果两个仓库都能正常列出包数说明配置基本没问题。再做一次真实安装验证试装一个依赖链较长的包nginx就是不错的选择dnf install -y nginx安装输出的下载阶段会显示URL比如Downloading from: http://192.168.1.10/yum/9.2/AppStream/看到这个就证明流量确实走的是内网源。如果还要更严格可以用一台断外网的最小化Rocky9.2机器来测这在第6章会展开。Rocky9.2里的yum命令其实是dnf的符号链接写法上两者都能用。实验目的是“配置yum源”也好、“查看yum源”也好最终落点都是让dnf的每个请求尽量命中内网而不是去外网碰运气。5. 避坑与常见问题我从零建源时翻车的5个地方自建源本身不复杂但坑很集中。以下5条是我在实际部署和维护中反复遇到的现象每条按“现象、原因、解决”三段写可以直接对照排查。如果你们踩到的坑不在列表里按同样思路去看dnf的报错、httpd的access_log和SELinux的avc日志基本都能定位。5.1 客户端报“Could not retrieve mirrorlist”卡半天才开始装包现象执行dnf install时长时间卡在类似Could not retrieve mirrorlist http://mirrorlist.rockylinux.org/...的报错然后才执行本地源安装。原因客户端/etc/yum.repos.d/下还保留着Rocky官方源文件而该机器无法访问外网或DNS解析失败。dnf尝试所有官方源超时后才会轮到本地源导致每次操作都被拖慢。解决按第4.1节把Rocky-*.repo全部移到bak目录然后执行dnf clean all。如果只是临时用一下也可以dnf --disablereporocky-* install xxx但批量化部署还是直接移走文件最干净。5.2 报错“repodata/repomd.xml”返回404现象dnf makecache时报错提示Status: 404 Not Found以及具体的repomd.xml路径。原因大概率是baseurl路径写得不对。常见情况有三种BaseOS写成小写baseos、目录层级多写了一层/少写了一层、某个仓库根目录下根本没有repodata比如把rpm拷到了目录但没生成元数据。解决先用curl直接访问报错里的URL确认文件是否存在。curl -I http://192.168.1.10/yum/9.2/BaseOS/repodata/repomd.xml。如果文件确实不存在看目标目录结构是否带repodata没有就按第3.3节补createrepo_c。如果文件存在但dnf仍404再看httpd的access_log确认实际请求路径。5.3 AppStream模块信息一查一个空“module list”没有输出现象客户端dnf module list nginx显示无内容或者安装带模块的包时提示找不到模块元数据。原因AppStream的repodata是从ISO或镜像源原样同步的就没问题一旦有人用createrepo重新生成了AppStream的元数据却没有带modules.yaml.gz参数模块流信息就全部丢失。Rocky9的模块机制依赖这份文件压缩过又不起眼很容易被忽略。解决如果目标目录还保留着原始的AppStream/repodata直接恢复元数据如果已经重新生成过按第3.3节进入AppStream目录执行createrepo_c --modules modules.yaml.gz .再让客户端dnf clean all dnf makecache。5.4 客户端访问返回403服务端本机curl却正常现象客户端访问源URL返回403 Forbidden服务端在本地curl http://127.0.0.1/...却是200非常像网络问题排查半天。原因SELinux拦截。多半是两种情况一是源目录放在/var/www/html之外的路径比如/data/yumhttpd进程没有读取权限二是用了cp -a或rsync -X这类保留扩展属性的方式拷贝文件把ISO文件系统的SELinux上下文也带了过来。解决如果目录在/var/www/html外用semanage配置持久化上下文semanage fcontext -a -t httpd_sys_content_t /data/yum(/.*)?然后restorecon -R /data/yum。如果目录在html内但上下文不对直接chcon -R -t httpd_sys_content_t /var/www/html/yum。用ausearch查一下更确定ausearch -m avc -ts recent能直接看到被denied的类型。5.5 客户端连接超时或拒绝连接局域网内像根本没这台主机现象客户端repo文件里写的是主机名运行时dnf一直超时curl同样超时。如果改用IP一切正常。原因一方面可能是内网DNS没有这个主机名的解析记录dnf对域名解析失败会反复重试另一方面要检查服务端httpd是否真的监听在所有网卡上。执行ss -tlnp | grep :80如果看到监听地址是127.0.0.1:80那说明httpd或某个手工启动的服务只绑定了本地回环局域网自然访问不到。这类问题在手动执行python3 -m http.server调试服务时尤其常见。解决repo文件里优先写静态IP省去DNS解析环节如果必须用主机名先在客户端/etc/hosts里做映射。服务端监听地址不对时检查httpd.conf里的Listen配置改成Listen 0.0.0.0:80后重启httpd。做完这两步再curl验证。6. 把静态源做成内网的后悔药增量更新、多版本并存与验收技巧自建源最怕的不是搭不起来而是搭起来后不知道怎么更新、怎么验证。我最后留一个习惯性的做法把源做成可以增量更新的静态目录同时在客户端保留多版本切换能力。增量更新用rsync就够核心是同步整个仓库目录让repodata跟着一起更新#!/bin/bash MIRROR_TOP/mnt/mirror/rocky/9.2 YUM_TOP/var/www/html/yum/9.2 rsync -av --delete $MIRROR_TOP/BaseOS/ $YUM_TOP/BaseOS/ rsync -av --delete $MIRROR_TOP/AppStream/ $YUM_TOP/AppStream/注意这里源和目标路径末尾的/以及--delete参数它保证源端删除的包在本地也会被清掉避免客户端看到已不在源里的旧包。同步完成后不需要重启httpd因为httpd只是提供文件访问不缓存仓库内容。真正需要处理的是让客户端刷新元数据缓存否则客户端还在用旧repodata去拉包会容易出现404或版本落后。多版本并存也很简单目录结构按大版本分隔/var/www/html/yum/8.6/BaseOS /var/www/html/yum/9.2/BaseOS /var/www/html/yum/9.3/BaseOS客户端升级系统或切换版本时只需要改repo文件里baseurl的版本号路径然后执行dnf clean all dnf makecache。万一新版本源有问题再把路径改回去就是一颗现成的后悔药。最后说验收技巧。我会在一台干净的最小化Rocky9.2机器上断开外网只保留局域网连通直接跑一次dnf groupinstall Development Tools看所有依赖是否都从内网源命中。再配合一个简单命令确认服务端源的更新时间避免被客户端旧缓存迷惑curl -sI http://192.168.1.10/yum/9.2/BaseOS/repodata/repomd.xml | grep -i last-modified这条命令返回的时间就是源端元数据的最后修改时间。如果客户端报的包列表和你刚同步的不一致先看这个时间再决定要不要在客户端执行dnf clean all。我习惯把它写进crontab每天早上看一眼确保源挂掉或更新失败时能第一时间发现。这套方案救了我很多次希望帮到你。本文还有配套的精品资源点击获取