内网环境本地YUM源搭建实战:从依赖地狱到一键部署

发布时间:2026/10/15 18:34:17

内网环境本地YUM源搭建实战:从依赖地狱到一键部署 “又连不上外网了装个软件全他妈是依赖。”这句话是我前段时间在客户现场听到最多的一句抱怨。那台机器在隔离内网yum源全都指向公网装个nginx要一层层解决依赖最后手工rpm -ivh装了二十多个包才把环境跑起来。从那以后我就把“本地YUM源”当成了内网部署的第一优先级。如果你也遇到过类似场景这篇内容就是写给你的。所谓本地YUM源本质上就是把RPM包和仓库元数据放到一台内网服务器上再通过HTTP共享出去让内网其他机器直接用它作为软件源。它解决的痛点非常明确外网连不通、公网源不可用、批量部署时依赖地狱。适用范围包括隔离网环境、云内网、测试机房、生产内网只要你有“若干台机器需要装同一批软件”的需求这套东西就值得搭一次。搭建过程并不复杂核心就四步准备RPM包、生成repodata、发布HTTP服务、配置客户端repo文件。但里面坑不少。我会把每一步的原理、操作、踩坑经验全写出来尽量让你照着做完就能直接用。1. 内网环境下为什么绕不开本地YUM源1.1 每次“缺依赖”都想摔键盘在线环境下yum install nginx只是几秒钟的事。可一旦网络被隔离问题就完全不一样了。一个nginx可能要依赖pcre、openssl、zlib、gcc、make、glibc-devel等等。而每一个依赖还可能再有依赖。我曾经在一个最小化安装的系统上手动装过一套LNMP环境光依赖就整理了半张A4纸最后还有几个包和系统自带的版本冲突折腾到半夜。内网机器通常无法直接访问公网YUM仓库这是所有痛苦的根源。即便个别机器能通过代理上网大量客户端同时装包时公网带宽和源服务器压力也会让事情变得很不稳定。而本地YUM源是把软件包和依赖关系在内网这个“局域网超市”里先备好客户端只从内网取货稳定性和速度都完全可控。从管理角度看本地源还有一个好处你可以对软件版本做统一管控。线上环境全都指向同一个内网源那装出来的系统依赖版本就是一致的。不会出现一台机器openssl版本偏高、另一台偏低的问题这对后续排查问题帮助极大。1.2 本地YUM源的本质把“软件仓库”搬进内网我习惯把YUM源比作一个超市RPM包是货架上的商品repodata是商品索引目录repo文件是你手里的超市地址。在线环境里超市地址默认指向公网镜像内网环境里我们需要自己开一家超市然后通知所有客户端“以后来这家”。这里有一个容易混淆的点本地源和“本机光盘源”不是一回事。如果你只是单机临时用挂载ISO后用file://协议指向光盘那也叫源但只能这一台机器用。本文说“内网快速搭建本地YUM源”核心是多台机器共享一个仓库地址所以必须走HTTP或HTTPS。只有把仓库服务化、网络化才能真正发挥本地源的价值。2. 动手前先弄懂YUM源的三块基石2.1 RPM包从哪里来一个仓库的原始素材是RPM包。它的来源大致有三种我后面会分别给操作命令这里先讲清楚各自适用场景。第一系统ISO镜像。系统安装盘里自带了一个Packages目录里面有几千个基础RPM包。这个来源最快挂载ISO就能拿到包适合解决“最小化系统想装常用组件”的场景。缺点是版本相对固定包数量有限很多第三方软件比如nginx官方源、EPEL里的包它是没有的。第二公网镜像仓库同步。利用reposync把在线仓库整个或部分同步到本地比如CentOS的Base、Extras、EPEL。这种方式最完整仓库里的包和在线源几乎一致适合做长期维护的生产环境源。缺点是首次同步数据量大需要规划磁盘。第三从现有机器上收集。如果你内网已经有一台机器装好了目标软件可以使用yumdownloader把它和依赖全部抓下来再放到内网源里。这种方式最轻量适合“我只想让其他几台机器装同一个软件”的场景。缺点是每次需要什么软件都要先去联网机器上抓一次。三种方式不冲突在我常用的仓库里这三种来源的包会分别放在不同子目录避免混乱。2.2 repodata 是仓库的“索引”YUM客户端不是直接扫描目录里的RPM文件名来决定安装哪个包的而是读取一个叫repodata的目录。repodata里有primary.xml.gz、filelists.xml.gz、other.xml.gz、repomd.xml等文件。其中primary记录着每个RPM的名称、版本、架构、依赖关系filelists记录着包里包含哪些文件repomd.xml则是这些元数据的索引。打个比方你走进一家超市不可能把整个仓库翻个底朝天来找商品你得先看货架标签和商品目录。repodata就是这个目录。没有它客户端会直接报错说找不到仓库。生成repodata的工具是createrepo或createrepo_c。createrepo_c是C实现性能更好现在主流系统上createrepo命令基本就是它的软链。后面我会给具体命令。2.3 仓库的“门面”HTTP 服务有了RPM包和repodata还需要一个方式让别的机器能访问到。YUM客户端支持的协议包括file://、http://、https://、ftp://。其中file://只能本机用所以内网多机共享场景必须选后面三个。我推荐HTTP理由很简单配置轻、调试直观、客户端不用装额外工具。HTTPS当然更安全但内网环境下通常没有可信CA证书自己签发的证书反而会让客户端报错折腾一圈只为了防内网嗅探多数情况下不值当。HTTP服务用nginx或httpd都可以我更偏向nginx配置简洁、并发能力强也更适合批量部署时的大流量场景。仓库目录的发布结构通常是这样一层根目录是某个仓库的根根目录下是各种RPM包根目录下有repodata子目录。客户端repo文件里的baseurl要指向这个根目录。3. 快速搭建四步跑通一个能用、够用的内网源3.1 准备源服务器与目录规划先选一台机器当作源服务器。它不要求很高配置但磁盘一定要大。如果你准备同步完整BaseEPEL建议预留至少100GB空间。如果你只同步常用软件包二三十GB也够。这一点千万别拍脑袋我见过太多人仓库同步到一半把根分区写满的。目录规划我习惯这样分/data/yumrepo/centos-base系统基础包对应在线源的BaseOS/data/yumrepo/centos-extras外带组件对应Extras仓库/data/yumrepo/epelEPEL额外包对应EPEL/data/yumrepo/local自己用yumdownloader抓下来的小批量包这样划分的好处是不同来源的包不会混在一起createrepo时可以单独对每个目录操作。如果你把EPEL的包和Base的包放在同一个目录createrepo后客户端的依赖解析会变得混乱有时还会出现“包版本被覆盖”的幻觉排查起来很痛苦。创建目录的命令很简单mkdir -p /data/yumrepo/{centos-base,centos-extras,epel,local}3.2 采集RPM包的三种方式按需选择方式A从系统ISO提取基础包这个方式最快。把CentOS安装ISO传到源机器上或直接在光驱里挂载然后拷贝Packages目录mount -o loop /path/to/CentOS.iso /mnt/cdrom cp /mnt/cdrom/Packages/*.rpm /data/yumrepo/centos-base/ umount /mnt/cdrom注意新版CentOS/RedHat的ISO里可能没有单独的Packages目录而是有一个repodata结构。这种情况下直接整个ISO里的rpm包拷出来也可以但要注意版本对应关系。ISO里的包版本比较老安装软件时可能不如在线源的新但作为内网基础依赖源完全够用。方式B使用reposync同步在线仓库这是搭建生产级内网源最推荐的方法。先安装yum-utils工具yum install -y yum-utils假设你在联网环境下已经能访问公网仓库直接执行reposync -p /data/yumrepo/centos-base --repobaseos --repoidbaseos这里--repo指定要同步的仓库ID--repoid是等价写法。同步后会下载大量RPM包到指定目录。网络好的情况下Base仓库大约几GB到几十GBEPEL更大。如果想节省空间加--newest-only参数只保留每个包的最新版本不保留历史版本reposync -p /data/yumrepo/centos-base --repobaseos --newest-only同步时建议在screen或tmux里跑防止SSH断开导致中断。方式C从现有机器抓取依赖包如果你只是想把一台机器上已经装成功的软件复制到其他机器用yumdownloader最合适yum install -y yum-utils yumdownloader --resolve --destdir/data/yumrepo/local nginx--resolve会自动解析依赖并下载所有需要的RPM--destdir指定存放目录。这个过程得到的包可以直接放进本地仓库也可以直接拿U盘拷到离线机器上rpm -ivh。对于小型部署场景这个方式比同步整个仓库快得多。3.3 生成仓库元数据createrepo 详解无论包是从哪个来源收集的放进仓库目录后都要生成repodata。生成前先安装工具yum install -y createrepo_c然后对每个仓库目录执行createrepo /data/yumrepo/centos-base这时目录下会出现repodata子目录里面有repomd.xml以及primary.xml.gz等文件。createrepo默认是增量友好型的第二次对同一目录执行时会重新扫描并更新。如果包非常多建议加--update参数让它只处理新增有变化的包节省时间createrepo --update /data/yumrepo/centos-basecreaterepo输出的日志里能看到“Workers Finished”之类的提示看到“Total Packages”数量后基本就成功了。万一中途出错建议删掉repodata目录重新生成不要强行用坏的元数据。3.4 用HTTP把仓库发布出去RPM包和repodata都齐了接下来要让别的机器能访问。我用的是nginx举一个最小配置。安装nginxyum install -y nginx打开配置文件/etc/nginx/conf.d/yum.conf写入server { listen 8080; server_name 192.168.1.10; root /data/yumrepo; autoindex on; charset utf-8; location / { } }这里我特意建议用8080端口而不是80。原因很现实内网机器往往已经占用了80给别的web服务为了避免冲突源服务用8080是更稳妥的选择。autoindex on让浏览器可以直接打开目录列表也方便你用网页确认包是否放对了位置。启动nginx并检查systemctl start nginx systemctl enable nginx curl -I http://127.0.0.1:8080/centos-base/repodata/repomd.xml如果返回200 OK说明仓库已经以HTTP形式发布成功了。3.5 客户端配置repo文件客户端机器的配置非常简单在/etc/yum.repos.d/下新建一个local.repo[local-base] nameLocal CentOS Base baseurlhttp://192.168.1.10:8080/centos-base enabled1 gpgcheck0如果还有EPEL源同样加一个[local-epel] nameLocal EPEL baseurlhttp://192.168.1.10:8080/epel enabled1 gpgcheck0配置完成后一定要把原有repo文件禁用掉否则客户端还会尝试访问公网源。最简单粗暴的方式是改名mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak然后清理缓存并测试yum clean all yum makecache yum install -y nginx看到“Complete!”基本就说明本地源已经生效了。如果makecache报错优先检查baseurl路径是否正确、防火墙是否放行8080端口。提示如果客户端之前没有网络仓库的GPG key而我这里又设置了gpgcheck0是为了快速跑通。在生产里如果你包来自官方镜像建议把GPG key导入并保持gpgcheck1。命令行是rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7。没有对应key时强行gpgcheck1会大面积报错。4. 细节决定成败六个高频坑和避坑经验4.1 gpgcheck 与签名验证引发的诡异报错最常见也是最烦人的报错是Public key for xxx.rpm is not installed出现这个说明repo配置里gpgcheck1但本地没有对应的GPG公钥。有的包是第三方编译的本身就无签名你怎么导key都没用。解决办法有两类校验包来源如果包是官方镜像同步来的执行rpm --import导入key就好。如果包确实没有签名就只能把gpgcheck临时置为0。在内网封闭环境里gpgcheck0不算大问题毕竟攻击面已经很小。但如果你管理的机器需要等保合规建议还是保留校验必要的时候把官方GPG key文件放到repo里一并分发。4.2 客户端缓存与元数据不更新仓库里新加了包客户端却始终提示“No package found”。原因通常是客户端本地元数据缓存没刷新。yum查询依赖时优先读本地缓存不会每次重新拉取repodata。解决办法是yum clean all yum makecache我在自动化部署脚本里每次往仓库新增包之后都会在目标机器上先执行一次clean all再执行yum install避免各种“明明有包却装不上”的问题。4.3 架构不匹配导致“Nothing provides”错误有一类错误很坑提示“Nothing provides nginx needed by xxx”但你在源目录里明明看到有nginx rpm包。原因很可能是架构不匹配。比如你的仓库同时混了x86_64和aarch64的rpmcreaterepo会把这俩架构的包都记录进去。客户端在x86_64机器上yum可能会因为依赖解析的优先级问题选择了aarch64的包最终导致装不上。我建议从一开始就把架构分开目录/data/yumrepo/el7-x86_64/ /data/yumrepo/el8-x86_64/ /data/yumrepo/el9-aarch64/然后在不同的repo文件里指向对应的路径。这样的目录结构虽然看着繁琐但排查问题的时候能省下大量时间。4.4 磁盘空间撑爆仓库越来越大一个完整的EPEL仓库可能超过100GB如果再同步AppStream、PowerTools磁盘会很快见底。我经历过一次很尴尬的事createrepo跑到一半磁盘满了reposync的临时文件把根分区占了最后连删文件都删不动只能进救援模式。避坑方案仓库目录单独挂在大分区别放在/下面。同步时使用--newest-only只保留最新版本包。定期清理旧版本比如只保留近两个大版本的RPM。有条件的话做磁盘监控低于20%时自动告警。4.5 dnf 客户端下 repodata 不合规CentOS 8/9等使用dnf作为包管理器和yum对repodata的解析有些差异。你用老版本createrepo生成的元数据在dnf下可能报“Failed to download metadata for repo”或者模块相关错误。具体来说dnf要求AppStream仓库的repodata中包含modules.yaml如果你只是把RPM文件拷贝出来再createrepo模块信息会丢失这样你用dnf安装某些软件时就会失败。解决办法是同步官方仓库时保留它的repodata不要自己重建。reposync加--download-metadata参数就能做到reposync -p /data/yumrepo/centos8-appstream --repoappstream --download-metadata如果是自己用yumdownloader抓取的小批量包放到纯RPM仓库里就无所谓dnf也能正常识别。4.6 baseurl 路径写错导致404有一次我配置好所有东西客户端一直报“Cannot find a valid baseurl for repo”。我当时第一反应是防火墙折腾半天最后发现是baseurl路径多了一层目录。浏览器打开页面能看到目录列表但点进repodata就是404。建议配置完成后先用curl确认repodata路径能直接访问到curl -I http://192.168.1.10:8080/centos-base/repodata/repomd.xml别用浏览器只看目录根因为autoindex会显示路径但实际文件可能并不在那一层。repo文件里的baseurl是“仓库根目录”这个根目录下必须直接看到repodata文件夹不要多写一层。5. 进阶玩法从“能用”到“好用”的本地源5.1 定时增量同步保持源长期可用内网源不是搭完就一劳永逸的。软件版本会更新安全补丁会发布你需要定期把在线源的新包同步过来。结合reposync和createrepo放到crontab里就能自动完成。以CentOS 8的BaseOS为例定时任务可以这样写30 2 * * * reposync -p /data/yumrepo/centos-base --repobaseos --newest-only --download-metadata createrepo --update /data/yumrepo/centos-base这里--newest-only保证只增量下载最新版本--download-metadata将官方repodata直接下载下来省掉了本地createrepo的步骤。如果你选择保留多个版本就不要加--newest-only但磁盘会增长很快。同步之后记得在客户端执行yum clean all。如果客户端很多可以写一个简单的Shell脚本批量SSH过去执行。5.2 多仓库整合与优先级控制内网环境往往不止一个源。系统基础包是一个源EPEL是一个源自研软件包又是一个源。客户端repo文件里同时启用多个源时需要控制优先级避免某个包被EPEL的版本覆盖。安装priority插件yum install -y yum-plugin-priority在repo文件里标注优先级数字越小优先级越高[local-base] nameLocal Base baseurlhttp://192.168.1.10:8080/centos-base enabled1 gpgcheck0 priority1 [local-epel] nameLocal EPEL baseurlhttp://192.168.1.10:8080/epel enabled1 gpgcheck0 priority2这样即使EPEL里有更高版本的包yum也不会盲目升级保证了基础组件的稳定性。这个插件在大型集群里非常实用值得一装。5.3 批量安装时的性能优化内网源机器面对几十台甚至上百台客户端同时yum makecache时nginx默认配置可能会扛不住。主要瓶颈是worker连接数和文件描述符限制。我推荐的优化项worker_processes auto; worker_rlimit_nofile 65535; events { worker_connections 4096; }另外在server块里开启keepalive能减少重复建连的开销keepalive_timeout 65;如果客户端数量上千单台源服务器可能还是不够可以用rsync把仓库目录同步到两台以上服务器配合DNS轮询或负载均衡器。但99%的内网环境一台优化过的nginx源服务器都足够了。6. 常见问题速查表与排查思路现象可能原因处理方式yum makecache 卡住客户端连不上源服务器curl -I测试baseurl检查防火墙/端口报错404baseurl路径层级不对浏览器访问目录确认repodata所在层级报错Public key not installedgpgcheck1但没导keyrpm --import官方key或临时gpgcheck0提示No package found客户端元数据缓存过期yum clean all yum makecache报错Nothing providesRPM包架构不匹配或依赖缺失检查仓库包架构单独目录存放dnf模块报错AppStream模块信息丢失reposync加--download-metadata磁盘分区写满仓库包太多清理旧包--newest-only同步独立挂载大分区nginx启动失败端口被占用/配置语法错误nginx -t检查配置查看error.log6.1 一个真实的排查案例有一次在内网部署客户端一直报“Cannot find a valid baseurl for repo: local-base”。我第一反应是服务器没启动curl却很通畅。后来发现是SELinux拦截了nginx对非标准目录的访问。如果nginx日志里出现“Permission denied”很可能就是SELinux在捣乱。临时处理方式是调整SELinux布尔值让nginx能访问指定目录setsebool -P httpd_setrlimit 1 setsebool -P httpd_can_network_connect 1或者干脆把仓库目录迁移到/usr/share/nginx/html下这是nginx默认允许访问的目录。生产环境里遇到这类问题先看/var/log/nginx/error.log再决定是关SELinux还是调布尔值不要一上来就setenforce 0。6.2 离线机器零依赖安装小技巧如果只是几台机器需要装同一个软件没必要搭建完整仓库。直接在联网机器上用yumdownloader把软件和依赖下载到U盘yumdownloader --resolve --destdir/mnt/usb nginx然后到离线机器上执行cd /mnt/usb rpm -ivh *.rpm这种方式对临时需求非常高效。但如果要长期维护几十台机器反复做这种操作还是搭一个源更省心。我自己常用的策略是小批量临时需求用yumdownloader生产环境长期维护用reposync同步全量仓库。最后给点心得从最早在机房抱着系统光盘来回跑到现在一个目录加一个nginx搞定全内网的软件分发本地YUM源这个工具我一直舍不得丢。它最大的价值不是省流量而是让内网环境下的软件安装变成一件可预期、可自动化的事情。只要你把仓库目录规划好把createrepo和reposync的定时任务跑起来后续再补包、再扩机器成本都极低。我在实际维护里还有一个习惯每次新增大版本软件包后会在源目录下单独做一个README记录加包时间、来源机器、用途。这样半年后再看仓库不至于完全想不起来某些包是怎么进来的。别小看这个习惯运维类工作最怕就是“能跑但说不清”本地源也需要有人能说清楚它里面到底是什么。
延伸阅读

更多相关文章

2026/10/15 18:29:16

Linux C线程池实现:从pthread到任务队列的源码解析

简介:这份资源面向具备一定C语言基础、希望深入理解Linux多线程编程与并发模型的学习者,提供了一套可运行的简单线程池实现范例。内容围绕线程创建与管理、互斥锁与条件变量同步、任务队列设计、线程池初始化与销毁流程等核心知识点展开,帮助…

2026/10/15 18:29:16

AFSim 2.9.0 Linux源码编译指南:CMake配置与环境变量避坑全流程

简介:面向Linux平台源码编译AFSim2.9.0仿真工具集的实操指南,由作者依据自身完整编译经验整理,适合需要在Ubuntu等环境下搭建AFSim的仿真开发与研究人员参考。文档为单个PDF文件,体积约694KB,核心内容涵盖编译环境要求…

2026/10/15 19:54:47

Hive窗口函数实战:从GROUP BY到滑动窗口的进阶指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 19:54:47

FPGA上位机SDK迁移实战:从FrontPanel换到Pionway

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 19:54:47

目标检测分类与定位解耦:原理、策略与工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/15 19:49:47

纯几何与向量法的本质差异与协同解题策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 11:31:03

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/14 17:41:07

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/15 13:42:16

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/15 0:02:22

防关联浏览器哪个好?三款产品实测差异解析

新手做多店铺,最纠结的就是防关联浏览器选哪个。飞跨、网易、站斧这三款被问得最多,先给结论:要一体化省心、长期便宜,选站斧;要网易招牌和稳,选网易;预算紧做东南亚 Lazada,选飞跨。…

2026/10/15 0:02:22

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成

影刀RPA深度实战:大模型Fine-tuning定制RPA专用Prompt与指令生成 一、技术背景 大模型(LLM)在通用场景下表现强大,但当我们将 GPT-4 或 Qwen 直接用于生成影刀RPA操作指令和 XPath 定位时,准确率通常只有 40%-60%。原因…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑