简介:面向内网Linux服务器运维场景,这份资源演示如何在Rocky Linux 9.2上基于HTTP搭建局域网YUM源,解决无法访问互联网时批量安装、更新软件依赖的难题。内容从环境准备讲起,涵盖ISO镜像挂载、本地仓库配置、httpd服务部署,再到客户机baseurl修改与缓存刷新,全程提供可直接套用的命令和配置文件,并给出BaseOS与AppStream两个仓库的完整写法,适合需要为多台同版本机器统一软件源的系统管理员参考。资源为单个docx文档,共1个文件,压缩包大小120KB,全文步骤清晰、命令完整,便于边看边操作。已有1691人学习,对排查内网源配置问题、理解YUM仓库机制具有实用价值,也可迁移至其他基于RPM的Linux发行版。
1. 内网服务器的包管理痛点:为什么首选 HTTP 局域网 YUM 源
在几十台没有外网权限的 Rocky 9.2 服务器上装一个带依赖的软件,最磨人的不是软件本身,而是那串Requires: xxx.so。你可以在每台机器上挂 ISO 做本地 repo,但每台跑一遍mount、写一遍 repo 文件,节奏慢得让人怀疑人生。局域网里只要有那么一台能提供 HTTP 服务的机器把 DVD 镜像发布出去,剩下的客户机只要把 repo 里的baseurl从file://改成http://ip/...就行,升级、装包、内核补丁一把梭,包版本还能锁在同一屋檐下。
这个资源就是干这件事的最小可行方案:Rocky 9.2 的 DVD 镜像 + httpd + 一个挂在/var/www/html/opt下的目录,对外提供 BaseOS 和 AppStream 两个仓库。你不需要编译软件,不需要自己打 RPM,更不需要在每台机器上重复做本地源。适合的人群非常明确:内网离线环境下的运维工程师、实验室里几十台虚拟机统一装环境的人,以及刚把系统从 CentOS 7 迁到 Rocky 9、对 DNF/YUM 生态还有点生疏的人。
2. 镜像挂载与基础准备:Rocky 9.2 ISO 怎么变成可用仓库
2.1 先盘点环境:IP、系统版本、镜像路径
在动手之前,先把两台机器(或一台服务器加一群客户机)的角色和 IP 分清楚。典型部署是这样:
| 角色 | 主机名 | IP 地址 | 作用 |
|---|---|---|---|
| Yum 服务器 | linux1 | 192.168.15.100 | 挂载 ISO,运行 httpd |
| 客户端 | linux2 及更多 | 192.168.15.101 | 通过 HTTP 拉取软件包 |
系统版本统一是 Rocky-9.2-x86_64。这一步不是形式主义:BaseOS和AppStream两个仓库的目录结构在 9.x 里是固定的,后面所有路径都依赖这个布局。版本不一致,轻则 repo 枚举不到软件包,重则把别的发行版的仓库混进来,装出一堆不兼容的 glibc 也不是不可能。
镜像包 Rocky-9.2-x86_64-dvd.iso 建议放到/opt下。我是用 SecureFX 或 scp 推过去的,三四 GB 的文件在内网千兆环境下一两分钟就完事。传完顺手看一眼:
ls -lh /opt/Rocky-9.2-x86_64-dvd.iso如果体积连 1GB 都不到,说明拿到的可能是引导镜像而不是 DVD 完整包,后面的仓库枚举会缺一大批包。这一步的排查成本几乎为零,但很多人在传完文件之后就直接开始挂载,等到客户机报错才回来补查。
2.2 挂载 ISO:mount 命令别抄错
挂载是整个搭建过程中最容易“照抄翻车”的地方。原始文档里的命令是直接mount /opt/Rocky-9.2-x86_64-dvd.iso /var/www/html/opt,这里我建议加-o loop参数,并把 ISO 路径写完整。原因放在命令后面的参数说明里:
mkdir -p /var/www/html/opt mount -o loop /opt/Rocky-9.2-x86_64-dvd.iso /var/www/html/opt命令解释:-o loop让内核把 ISO 文件当作回环设备挂载,不需要真实的光驱或块设备;目标目录/var/www/html/opt正好位于 httpd 的默认站点目录/var/www/html下面,客户机通过http://192.168.15.100/opt/...访问时,实际读到的是挂载点里的内容。
参数说明:
-o loop:不加这个参数时,新版 mount 通常也能自动识别 ISO 为回环设备,但在部分内核配置或 systemd 接管挂载的情况下,会出现mount: /var/www/html/opt: 设备上没有剩余空间这种误导性报错。显式指定loop能绕开绝大部分隐式解析的坑。- 目标目录必须事先存在,mount 不会帮你创建。
mkdir -p加上-p参数是防止目录存在时报错。 - 挂载 ISO 不需要
-t iso9660,mount 能自动探测;强制指定反而可能在个别环境里触发文件系统探测异常。
挂载完成后做一次确认,这一步别跳:
ls /var/www/html/opt/能看见BaseOS、AppStream、EFI、images等目录,才算挂上了。如果ls出来只有 ISO 文件名一个孤零零的结果,或者目录是空的,说明挂载没有真正生效,回过去检查挂载参数和目录内容。
2.3 挂载持久化:先在 fstab 留一条,后面少踩一次雷
重启后 ISO 挂载会自动消失,这是 YUM 源搭完后的第二周里最常出现的问题。趁搭建的当下在/etc/fstab里追加一行,避免后续某天服务器重启时,客户机集体报 404:
/opt/Rocky-9.2-x86_64-dvd.iso /var/www/html/opt iso9660 loop,defaults 0 0这行的字段含义依次是:要挂载的源设备、挂载点、文件系统类型、挂载选项、是否 dump 备份、是否 fsck 检查。loop,defaults表示走回环设备并采用默认挂载选项,0 0表示不做备份也不做启动时 fsck。
加完这行后执行mount -a验证语法无误。fstab 写错最常见的后果是重启进入 emergency mode,所以这个验证动作等于给自己的运维工作买了一份后悔药。
3. 服务器端仓库配置与 httpd 启动:从 file:// 到 http:// 的关键一跳
3.1 接管 /etc/yum.repos.d/:默认仓库的清理逻辑
Rocky 9.2 装完系统后,/etc/yum.repos.d/下会有rocky.repo、rocky-extras.repo之类的文件,指向公网镜像源。在内网环境下这些文件没有任何意义,反而会在yum makecache时反复超时拖慢缓存构建。处理方式我建议用备份接管,而不是直接删:
cd /etc/yum.repos.d/ mkdir backup && mv *.repo backup/这样先把默认源归位,再新建自己的源文件。*.repo这个通配只匹配后缀为.repo的文件,不会误伤其他配置。备份目录比直接rm稳,万一后面要恢复公网源,还有后悔药吃。
然后新建本地源配置文件:
vi /etc/yum.repos.d/local.repo注意路径是/etc/yum.repos.d/,原文里出现过/etc/yum.repo.d/少一个s的笔误,这种拼写错误在执行命令时会被正常接受但找不到目录,后面排查起来非常费劲。
3.2 新建 local.repo:仓库参数逐项说明
在local.repo中写入以下内容:
[Rocky-BaseOS] name=Rocky-BaseOS (local) baseurl=file:///var/www/html/opt/BaseOS enabled=1 gpgcheck=0 [Rocky-AppStream] name=Rocky-AppStream (local) baseurl=file:///var/www/html/opt/AppStream enabled=1 gpgcheck=0这里有几个点值得多说一句:
baseurl=file:///var/www/html/opt/BaseOS,注意是三个斜杠。file://后面跟的是绝对路径,协议分隔符和路径之间至少需要三个斜杠才能被正确解析。写少了会直接报仓库加载错误,看不到具体包列表。- 路径末尾的
/可写可不写,DNF 会自动兼容,但保持路径干净对排查有好处。 gpgcheck=0在内网环境是务实的选择。DVD 镜像自带的 RPM 签名信息在 repodata 里有,但很多内网环境时钟不同步,或者镜像被二次裁剪过,签名校验会引发一堆不必要的麻烦。这个实验室场景下先关了,跑通之后再决定要不要开。enabled=1表示仓库默认启用。这是仓库组的默认值,写出来更明确,也方便以后快速改成0做灰度验证。
仓库文件写完后,先在本机验证一下本地源能不能用:
yum clean all yum makecache yum repolistyum repolist的输出应该列出 Rocky-BaseOS 和 Rocky-AppStream 两个仓库,并且后面带一个非零的包数量。如果这里包数量是 0,后面 httpd 的安装就不用往下走了,先回去检查挂载目录的层级结构对不对。
3.3 安装并启动 httpd:服务起来了,还得把门打开
httpd 本身可以从刚才配好的本地源里直接装:
yum install -y httpd systemctl start httpd systemctl enable httpd systemctl status httpd解释一下这三条命令的各自目的:yum install -y httpd从本地仓库解析 httpd 包的依赖清单并全部安装,-y参数跳过交互确认,适合批量操作;systemctl start httpd让服务在当前会话内运行;systemctl enable httpd把服务注册为开机启动项,这样重启后不用手动再拉起来。
systemctl status httpd是验证动作,输出里看到active (running)才算通过。如果是failed,最可能的原因是 80 端口被占用,用ss -lntp | grep :80查一下占用进程,或者看/var/log/httpd/error_log的最后几行。
接下来是访问控制的处理。原始文档里的做法是直接关防火墙和 SELinux:
systemctl stop firewalld setenforce 0这两条命令的作用是把服务器的防火墙和 SELinux 临时关掉,让客户机能直接通过 HTTP 访问/opt目录。在隔离的内网环境这是一个权衡过的决定:如果你所在的局域网本身没有外部暴露面,短时间内用这种方式带过去可以。但如果环境规范要求必须开防火墙,更合适的做法是只放行 80 端口,不过这是进阶章节要讲的事,这里先把链路跑通。
完成上面这些步骤后,本机自测一次:
curl -I http://192.168.15.100/opt/BaseOS/如果返回HTTP/1.1 200 OK,服务器端已经具备对外提供仓库的能力,可以转到客户机配置了。
4. 客户机接入与验证:yum clean all、makecache 与 yum list
4.1 客户机的 repo 文件:baseurl 从 file 换成 http
客户机的配置逻辑跟服务器端几乎一样,唯一实质变化是baseurl的协议从file://改成http://ip/路径。在客户机 linux2 上,编辑/etc/yum.repos.d/local.repo:
[Rocky-BaseOS] name=Rocky-BaseOS (LAN) baseurl=http://192.168.15.100/opt/BaseOS enabled=1 gpgcheck=0 [Rocky-AppStream] name=Rocky-AppStream (LAN) baseurl=http://192.168.15.100/opt/AppStream enabled=1 gpgcheck=0同样地,客户机默认的/etc/yum.repos.d/下那些指向外网的.repo文件也应该先移走或备份,否则执行yum makecache时它们会拖累整体耗时,甚至在某些网络策略下直接超时中断:
cd /etc/yum.repos.d/ mkdir backup && mv *.repo backup/这里有个小细节值得单独说一句:原文档里出现过rm -rf !( local.repo)这种写法,!( )是 bash 的 extglob 扩展模式,表示“除了括号里的之外”。这个命令在默认 shell 下不一定有效,因为 bash 默认没开extglob,直接跑会报语法错误。所以客户机端我建议用 mv 而不是 rm 那套,既避免命令本身不生效带来的困惑,也避免手误删掉不该删的文件。
4.2 缓存清理与重建:为什么两步都不能省
配置好 repo 文件之后,执行:
yum clean all yum makecacheyum clean all清空元数据缓存。DNF/YUM 会把仓库的 repomd.xml 和包列表缓存到/var/cache/dnf下面,当baseurl更换之后,旧缓存指向的仓库地址已经失效,如果不清理,makecache可能直接沿用旧缓存,导致你看到的一直是旧仓库列表。这一步偷懒的话,大概率会在yum install时遇到“Could not resolve host”或者“Failed to download metadata”。
yum makecache请求每个仓库的repomd.xml、primary.xml.gz等元数据文件,并解析生成缓存的包名版本索引。这一步能通过,说明从客户机到服务器 httpd 的通路、仓库目录层级、元数据完整性三项都正确。makecache比较慢是正常的,因为它要从服务器把几百 MB 的元数据拉下来,等个几十秒到几分钟都常见,卡住不动再考虑是不是 80 端口被防火墙挡了。
4.3 用 yum list 做最终验证:看到软件包才算数
缓存建好之后,用yum list检查仓库内容是否完整可见:
yum list | head -50 yum list | wc -lyum list输出包含已安装包、可用包和更新包三类。这里建议关注两件事:一是可用包总数量不是 0,Rocky 9.2 DVD 镜像的 BaseOS 加上 AppStream 的可用包总量通常在几千的量级;二是能从中看到你后续要装的软件包名,比如yum list httpd能返回一个版本号而不是空结果。
如果yum list输出的仓库前缀带的是@System,那说明仓库信息没有被正确加载,多半是 repo 文件路径写错了或者备份时把自己的local.repo也一起挪走了。此时用ls /etc/yum.repos.d/检查一下文件是否存在,再cat确认 baseurl 无拼写错误。
4.4 新增客户机的批量接入流程
第三台第四台机器要接入,不需要在每台上做任何高级操作,流程就是固定四步:
# 1. 备份并清空默认仓库 mkdir -p /etc/yum.repos.d/backup mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup/ # 2. 写入本地局域网源配置 cat > /etc/yum.repos.d/local.repo <<'EOF' [Rocky-BaseOS] name=Rocky-BaseOS (LAN) baseurl=http://192.168.15.100/opt/BaseOS enabled=1 gpgcheck=0 [Rocky-AppStream] name=Rocky-AppStream (LAN) baseurl=http://192.168.15.100/opt/AppStream enabled=1 gpgcheck=0 EOF # 3. 清理缓存 yum clean all # 4. 重建缓存 yum makecache这四步里,把 repo 文件用 heredoc 方式一次性写入,比 vi 手工输入更不容易出错,而且可以做成脚本循环批量下发。baseurl那一段是唯一需要根据实际环境替换的变量,其他内容对同一批客户机完全一致。下发给新机器时,把 IP 换成 Yum 服务器的地址就行。
5. 避坑指南:从路径拼写到 SELinux 的五次翻车
5.1 现象:挂载 ISO 后仓库目录是空的
服务器上yum makecache报Error: Failed to download metadata for repo 'Rocky-BaseOS': Cannot download repomd.xml,客户机那边也找不到任何包。用ls /var/www/html/opt看却明明有 BaseOS 和 AppStream 目录。
原因:ISO 挂载成功后,BaseOS 目录下的repodata是只读的,但很多人检查时只看目录存在,没有进一步确认repodata子目录是否完整。另一种可能是一次没挂干净,第二次挂载把目录叠在了旧内容上。
解决:先umount /var/www/html/opt,再重新挂载。挂载后执行ls /var/www/html/opt/BaseOS,确认有repodata目录而不是只有Packages子目录。repodata才是 YUM 元数据所在的位置,没有它,仓库就只是个空壳。
5.2 现象:rm -rf !(local.repo) 报语法错误
在 bash 里执行原文档中的清理命令,报syntax error near unexpected token '('。
原因:!(pattern)属于 extglob 扩展语法,bash 默认没有开启 extglob 选项,因此!后面跟(被解析成了负逻辑与子 shell,语法直接失败。很多复制粘贴的人在这里就停下来,之后的操作全乱套。
解决:执行前先shopt -s extglob再跑命令。或者干脆换用 mv 备份的思路,效果相同且更安全。如果已经开了 extglob,写成rm -rf !(local.repo)时注意括号内外不要有空格,原文档里!( local.repo)的写法在 extglob 模式下匹配的也是带空格的错误模式,删不干净,容易留下残留文件干扰后续缓存构建。
5.3 现象:客户机 makecache 长时间超时或 404
客户机yum makecache卡在某个仓库一直转圈,最后超时中断,或者直接报 404。
原因:baseurl里 IP 写错。原始文档里出现过http://192.168.1.100/opt/...,而服务器真实 IP 是192.168.15.100。这种 192.168 段的笔误特别隐蔽,一眼看去都像对的,不逐一比对根本发现不了。
解决:在客户机上先用curl -I http://192.168.15.100/opt/BaseOS/repodata/repomd.xml,如果返回 200,说明网络层通着,问题就在 baseurl 拼写;如果返回 404,检查服务器目录层级;如果是连接超时,回头查防火墙。curl 这一步建议写进流程清单,每次配完源先 curl 一遍,能省大量排查时间。
5.4 现象:curl 返回 403 而不是 200
服务器上curl http://192.168.15.100/opt/BaseOS/返回403 Forbidden,而不是预期的200 OK。
原因:SELinux 处于 enforcing 状态,httpd 对/var/www/html下未标记为httpd_sys_content_t的内容默认拒绝读取。挂载点目录用ls -Z检查,上下文往往显示为default_t或var_t,httpd 没有读取权限。
解决:先用chcon -R -t httpd_sys_content_t /var/www/html/opt/临时打标,验证 curl 恢复 200 后,再用semanage fcontext -a -t httpd_sys_content_t '/var/www/html/opt(/.*)?'和restorecon -Rv /var/www/html/opt/把策略持久化。如果整个环境允许禁用 SELinux,直接setenforce 0能绕过,但这不是优先选项,尤其对于需要长期稳定运行的生产内网环境。
5.5 现象:服务器重启后客户机 yum 全部 404
服务器重启后,客户机yum makecache报HTTP Error 404 - Not Found,但服务器上 httpd 服务看着是正常的。
原因:ISO 挂载是临时 mount,重启后/var/www/html/opt变成了空目录,httpd 正常返回 200 但目录列表是空的,请求 repomd.xml 时自然 404。fstab 里没写挂载项,或者写错了路径导致挂载没生效。
解决:在/etc/fstab里补 ISO 挂载项,重挂载前先用mount -a验证。另外systemctl start httpd如果没配enable,重启后 httpd 服务也没起来,客户机看到的是 connection refused,症状不同,排查时要一并检查服务状态和挂载状态两条线。
6. 让源更持久:fstab 持久化、防火墙细化与多发行版复用
6.1 持久化挂载:把 DVD 内容搬到磁盘是最稳的做法
基于 ISO 挂载搭建的源,最大的软肋就是重启。即使 fstab 写对了,ISO 文件还在/opt下,重启后文件系统挂载依赖顺序偶尔也会慢半拍或者出错。更稳妥的做法是把 ISO 内容全部复制到磁盘目录,一劳永逸:
mkdir /var/www/html/rocky9 cp -a /var/www/html/opt/* /var/www/html/rocky9/这样做的直接好处有三个:一是访问路径从挂载点换成普通目录,不再依赖挂载时序;二是后续如果要对仓库做增量,或者对个别包做替换,可以直接在磁盘目录上操作,不需要重新制作 ISO;三是源文件可以长期保留在/opt,想重建随时可以重新复制。
cp -a会保留属主、权限、符号链接,目录结构跟 ISO 内完全一致。复制完成后,把服务器端和客户端的baseurl指向/var/www/html/rocky9/BaseOS和/var/www/html/rocky9/AppStream,再yum clean all && yum makecache一遍就能无缝切换。
6.2 防火墙不关也能跑:仅放行 80 端口
之前章节为了先把链路跑通,直接关掉了 firewalld。到了生产环境,该放行的放行,不该关的就别关。把关闭操作替换成精确放行:
systemctl enable --now httpd firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=192.168.15.0/24 port port=80 protocol=tcp accept' firewall-cmd --reload firewall-cmd --list-all这条富规则的含义是:仅允许192.168.15.0/24网段的机器访问本机 80 端口,来自其他网段的请求继续保持防火墙默认拒绝。这样做的好处是,客户机不管怎么换 IP,只要在同一个网段就能访问;服务器自身暴露面也压缩到最小,比直接停防火墙更站得住脚。
SELinux 同理,推荐保留 enforcing,用semanage fcontext给目录打标签,而不是在生产环境用setenforce 0一关了之。之前踩过的 403 坑,在正确打标后不会再出现,服务器的整体安全基线也保住了。
6.3 同一方案扩展到 CentOS 8/9、AlmaLinux
这个搭建套路不是 Rocky 9.2 独占。基于 RPM 的发行版,镜像内目录结构都遵循BaseOS+AppStream的规律,唯一差异在仓库元数据的位置上。CentOS 8 的 ISO 里同样有BaseOS和AppStream两个目录,AlmaLinux 9 与 Rocky 9 几乎一致;CentOS 7 则是Packages一个目录兜底,连BaseOS和AppStream的拆分都没有。
需要调整的只有baseurl指向的目录层级。比如 CentOS 7 镜像挂载到/var/www/html/centos7后,repo 文件写法变成:
[base] name=CentOS-7 - Base (LAN) baseurl=http://192.168.15.100/centos7/ enabled=1 gpgcheck=0其余动作——挂载、清除默认 repo、makecache、验证——完全一致。你在 Rocky 9.2 上跑通了这套流程,迁移到其他发行版时只花在改目录路径上的时间,不会超过十分钟。
从那以后我每次给内网机器配源,都会强制走一遍“挂载验证 → curl 自测 → 客户机 curl 验证 → yum list 出包”的流程,重启机器前还会去/etc/fstab确认挂载项还在。这套习惯帮我挡掉了不少半夜里客户机集体 404 的折腾,希望帮到你。
本文还有配套的精品资源,点击获取