YUM/DNF 软件源完全指南:自建内网 yum 源、客户端 .repo 配置、以及 25 个常用命令速查
一两台机器装软件用官方源没问题,到了几十台上百台统一装机、内网离线、要稳定可复现的部署环境时就该自建 yum 源了。本文从 0 开始用 createrepo_c + Nginx 搭一个支持增量更新、每天自动同步、几百台并发不卡的内网软件源,再讲客户端 .repo 文件每个字段怎么写、公网/内网源怎么切,最后把生产上最常用的 25 条 yum/dnf 命令按《查/装/更/删/源/排障》六类全部列好示例。
YUM/DNF 软件源完全指南:自建内网 yum 源、客户端 .repo 配置、以及 25 个常用命令速查
一两台测试机
yum install nginx404 了,大不了sed换个阿里云源就行;到了生产 100+ 台同一批部署,今天上游同步一半一半不同步、明天出口带宽被 100 台同时拉镜像打满、后天合规审计要求你所有装的包必须内网可追溯——这时候就该自己搭内网 yum 源了。本文把完整链路拆成三段:① 0→1 搭一台内网源(createrepo_c + Nginx + 自动增量同步脚本);② 客户端 .repo 文件逐字段讲解 + 推荐模板直接抄;③ 25 条生产天天用的 yum/dnf 命令按类别分好示例。最后加 7 个最常见的坑(repomd.xml 签名失败、rpmdb 坏了、No package available、mirrorlist 卡)的解决命令,真碰到时直接跑。
一、前置:你到底需不需要自建源?yum 和 dnf 是什么关系?
0.1 什么时候该自建内网 yum 源
| 场景 | 需要自建? | 痛点 |
|---|---|---|
| 1-5 台机器测试/个人用 | ❌ 直接换清华/阿里云镜像就行 | 自建反而徒增维护 |
| 内网机器不能上公网(隔离环境/等保合规) | ✅ 必须 | 没源装不了任何包 |
| 统一部署 30+ 台要批量安装同样版本 | ✅ 建议 | 公网源版本每天漂移,这次装的和下次装的不一样 |
| 出口带宽小、拉包慢/偶发 404/TimeOut | ✅ 建议 | 内网源走千兆/万兆局域网 1GB rpm 几秒下完 |
| 需要把自己打的 rpm(自研包、业务程序包)发布给所有机器 | ✅ 必须 | 不能用官方源装自己写的程序 |
| 合规审计:所有安装包必须可追溯、签名在本地 | ✅ 必须 | 审计 log 要求能还原每台装了谁发布的包 |
0.2 yum vs dnf vs rpm(一张表理清关系)
| 工具 | 层级 | 能处理依赖吗? | 现状 |
|---|---|---|---|
| rpm | 底层:单个包安装器 | ❌ 不处理依赖,缺啥直接报错 | 所有 RHEL 系发行版都装,是最底层 |
| yum (Yellowdog Updater Modified) | 上层:包管理器(基于 rpm) | ✅ 自动解依赖、下包、安装 | RHEL 7 / CentOS 7 及以前的默认 |
| dnf (Dandified YUM) | 上层:yum 的替代品 | ✅ 更聪明的依赖算法、更快、支持模块化 | RHEL 8 / Rocky 8 / AlmaLinux 8 起的默认,RHEL 9 上 yum 命令其实是软链接→dnf |
记忆技巧:你打
yum install在 RHEL 9 上实际跑的是 dnf,命令几乎全兼容,99% 的命令把 yum 换成 dnf 结果一样。下面所有示例用 yum 写,说明 dnf 同样适用,只有涉及 dnf5 新特性时会单独标出。
0.3 软件源(repo)文件在哪?
# 配置目录:所有 *.repo 文件,每个文件可以包含多个源([id] 一段算一个)
ls /etc/yum.repos.d/
# 主配置(全局,一般不用改,除非改 keepcache、cachedir、retries)
cat /etc/yum.conf
# dnf 的等价主配置:
cat /etc/dnf/dnf.conf二、方案选型:3 种搭建方式选哪个?
| 方案 | 适用规模 | 优点 | 缺点 |
|---|---|---|---|
| A. Nginx 静态 + createrepo_c ⭐ 本文推荐 | 中小团队 5~200 台 | 最简单、零依赖、稳定、增量更新成本低、配置一目了然 | 没 UI、没生命周期管理 |
| B. reposync 全量同步官方镜像 | 大学镜像站/大型企业 1000+ 台 | 100% 兼容官方源、所有包都有 | 单 Rocky 9 一个架构就 150G,同步慢(几小时~天级)、流量大 |
| C. Pulp / Katello / Foreman | 大型企业/合规严苛(金融、政企) | Web UI、合规签名、包生命周期(dev→staging→prod)、漏洞扫描 | 太厚重,部署+维护要 2 个人 |
99% 的运维团队其实只需要方案 A,下面就按方案 A 从零搭,所有命令在 Rocky Linux 9(兼容 RHEL 8/9 / AlmaLinux 8/9 / CentOS Stream 8/9)上验证过。
三、方案 A:Nginx + createrepo_c 从零搭内网源
假设你有一台 2C4G + 200G SSD 的内网机器(这个配置承载 200 台客户端并发非常轻松):
- 主机名:
yum-repo.infra.local - 内网 IP:
10.0.0.100 - 操作系统:Rocky Linux 9(RHEL 8/9 系列)
- 对外协议:HTTP(80 端口,内网简单;公网场景后面给 Nginx HTTPS + BasicAuth 的升级配置)
2.1 第 1 步:安装基础软件
# ---- Rocky 9 / RHEL 9 ----
dnf install -y nginx createrepo_c rsync yum-utils dnf-plugins-core
# createrepo_c:C 语言版生成 repodata,比老 createrepo(python) 快 10 倍
# yum-utils / dnf-plugins-core:提供 reposync / config-manager
# 启动并开机自启 Nginx
systemctl enable --now nginx
# firewalld 放行 80
firewall-cmd --permanent --add-service=http
firewall-cmd --reload
# SELinux:Nginx 默认可读取 /var/www(上下文 httpd_sys_content_t),用 restorecon 确保上下文正确
restorecon -Rv /usr/share/nginx/html /var/www 2>/dev/null
# 注:httpd_enable_homedirs 控制的是 httpd 访问 /home 家目录,与 /var/www 无关,不要混用
# 如果后面 Nginx 报 403 直接:setenforce 0 先验证是不是 SELinux,再细调2.2 第 2 步:目录规划
# 统一放 /var/www/yum,不同发行版+版本+架构分目录(一个源服务器可以同时服务 el7 el8 el9)
mkdir -p /var/www/yum/{el7,el8,el9}/x86_64/{baseos,appstream,extras,epel,custom}
chown -R nginx:nginx /var/www/yum
chmod -R 755 /var/www/yum
tree -L 3 /var/www/yum
# 应该是:
# /var/www/yum
# ├── el7/...
# ├── el8/...
# └── el9/x86_64/
# ├── baseos/ ← Rocky/Red Hat 基础包
# ├── appstream/ ← 带 modularity 的软件包(nodejs/postgresql 多版本)
# ├── extras/ ← 驱动/小众工具
# ├── epel/ ← EPEL(Extra Packages for Enterprise Linux)
# └── custom/ ← 我们自己打的业务 RPM(必须单独目录,别和官方混)2.3 第 3 步:往源里放 RPM 包(3 种常用方法)
源本质就是一个包含 .rpm 文件的目录 + 一份 repodata 索引。放 rpm 有三种策略,按你场景挑:
✅ 方法 1:yumdownloader(只下你明确需要的包+依赖,省空间)⭐最常用
# 装 dnf-plugins-core 就有 yumdownloader
# 例:我要在 el9 上给内网所有机器准备 nginx + keepalived + redis 包 + 它们的所有依赖
DEST=/var/www/yum/el9/x86_64/custom
mkdir -p "$DEST"
cd "$DEST"
# --resolve:连依赖一起下(关键!不然内网机装就会缺 .so)
# --alldeps:递归抓全所有依赖
# --archlist=x86_64,noarch:只抓这俩架构,不抓 i686(省一半)
dnf download \
--resolve --alldeps \
--archlist=x86_64,noarch \
--destdir="$DEST" \
nginx keepalived redis python3-pip jq vim-enhanced htop
# 下完你会看到目录里几百个 rpm,包括 zlib、pcre、openssl 这些依赖,全部是内网可安装的
ls -1 "$DEST" | wc -l✅ 方法 2:reposync(从公网镜像完整同步一个 repo 的全部包)
适合你要完整镜像官方的 BaseOS/AppStream,体积大,只建议有 300G+ 磁盘时用:
# 查看当前已启用哪些源
dnf repolist --enabled
# repo id repo name
# baseos Rocky Linux 9 - BaseOS
# appstream Rocky Linux 9 - AppStream
# extras Rocky Linux 9 - Extras
# 同步 el9 baseos 到我们本地目录(-n=newest-only 只同步最新版本,省一半空间;--delete 清掉上游已删除的包)
reposync \
--repoid=baseos \
--arch=x86_64 \
--download-path=/var/www/yum/el9/x86_64/baseos \
--download-metadata \
--newest-only \
--delete
# 同样同步 appstream / extras
for r in appstream extras epel; do
reposync --repoid=$r --arch=x86_64 \
--download-path=/var/www/yum/el9/x86_64/$r \
--download-metadata --newest-only --delete
done✅ 方法 3:手工拷包(你自己打的业务 rpm / 供应商给的驱动 rpm)
cp /opt/your-company-build/*.rpm /var/www/yum/el9/x86_64/custom/
chown nginx:nginx /var/www/yum/el9/x86_64/custom/*.rpm2.4 第 4 步:生成 repodata(createrepo_c,必须做!不然客户端报 404)
这一步是所有新人最容易忘的。只放了 rpm,没生成 repodata/repomd.xml → 客户端永远是 No package xxx available / 404 Not Found。
# 第一次全量生成
createrepo_c /var/www/yum/el9/x86_64/baseos
createrepo_c /var/www/yum/el9/x86_64/appstream
createrepo_c /var/www/yum/el9/x86_64/extras
createrepo_c /var/www/yum/el9/x86_64/custom
# 以后每天加新包之后用 --update 增量更新(秒级,不用重新遍历所有包)⭐ 推荐
createrepo_c --update /var/www/yum/el9/x86_64/custom
# 如果源里有 @group 组安装(比如 yum groupinstall "Development Tools"),要把 comps.xml 也 import 进去
# comps.xml 从官方 ISO 里拿,或从同步下来的 baseos 仓库 repodata/*-comps.xml.xz 解压后
createrepo_c -g comps-el9.xml --update /var/www/yum/el9/x86_64/baseos生成后每个子目录应该长这样(repodata 就是索引目录):
/var/www/yum/el9/x86_64/custom
├── repodata/
│ ├── 0123...-primary.xml.gz
│ ├── 4567...-filelists.xml.gz
│ ├── 89ab...-other.xml.gz
│ └── repomd.xml ← 索引头,客户端就找这个
├── nginx-1.24*.rpm
├── openssl-3*.rpm
└── ...2.5 第 5 步:Nginx 配置静态文件服务
编辑 /etc/nginx/conf.d/yum-repo.conf:
server {
listen 80;
server_name yum-repo.infra.local 10.0.0.100;
root /var/www/yum;
charset utf-8;
# 索引页(看目录,方便检查/浏览器直接下包)
autoindex on;
autoindex_exact_size off;
autoindex_localtime on;
# 性能参数:大文件下载 sendfile 省拷贝
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 单连接限速(可选,防止一台机器占满带宽)
# limit_rate 5m;
# 允许 range(断点续传,大 rpm 好)
max_ranges 8;
# 日志
access_log /var/log/nginx/yum-repo-access.log;
error_log /var/log/nginx/yum-repo-error.log;
# repomd.xml 不缓存(防止客户端拿旧索引)
location ~* /repomd\.xml$ {
add_header Cache-Control "no-store, no-cache";
}
# 其他文件缓存 10 分钟
location / {
try_files $uri $uri/ =404;
expires 10m;
}
}# 检查 nginx 语法 + 重载
nginx -t
systemctl reload nginx立刻验证(任何客户端都可以):
# 返回 xml 就 OK(403/404 都说明哪里挂了)
curl -I http://10.0.0.100/el9/x86_64/custom/repodata/repomd.xml
# HTTP/1.1 200 OK ... Content-Type: application/xml
# 浏览一下目录
curl -s http://10.0.0.100/el9/x86_64/custom/ | head -202.6 第 6 步:写自动同步脚本 + systemd timer(每天 03:00 增量同步)
cat > /usr/local/sbin/yum-repo-sync.sh <<'BASH'
#!/usr/bin/env bash
set -euo pipefail
LOG=/var/log/yum-repo-sync.log
exec &> >(tee -a "$LOG")
echo "[$(date)] ==== sync start ==="
BASE=/var/www/yum
chown -R nginx:nginx "$BASE"
# 1) 如果配置了 reposync,从上游同步(按你实际需要,注释就是没开)
# for repo in baseos appstream extras; do
# reposync --repoid=$repo --arch=x86_64 --download-path=$BASE/el9/x86_64/$repo \
# --download-metadata --newest-only --delete
# done
# 2) createrepo_c --update 增量生成 repodata(秒级)
for d in baseos appstream extras epel custom; do
dir="$BASE/el9/x86_64/$d"
[ -d "$dir" ] || continue
echo "[$(date)] update repodata: $dir"
# 如果你有 comps 组文件:加 -g /var/www/yum/comps-el9.xml
createrepo_c --update --workers=4 "$dir"
done
chown -R nginx:nginx "$BASE"
echo "[$(date)] ==== sync done ==="
BASH
chmod +x /usr/local/sbin/yum-repo-sync.sh
# 手动跑一次验证
/usr/local/sbin/yum-repo-sync.sh然后用 systemd timer 定时(比 cron 好,有日志有状态):
# /etc/systemd/system/yum-repo-sync.service
[Unit]
Description=Daily YUM repo sync & createrepo
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/yum-repo-sync.sh
Nice=10
IOSchedulingClass=2
IOSchedulingPriority=7# /etc/systemd/system/yum-repo-sync.timer
[Unit]
Description=Run yum-repo-sync daily at 03:00
[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true
[Install]
WantedBy=timers.targetsystemctl daemon-reload
systemctl enable --now yum-repo-sync.timer
# 查看所有已注册 timer
systemctl list-timers yum-repo-sync.timer四、客户端:.repo 文件逐字段讲 + 模板直接抄
3.1 /etc/yum.repos.d/xxx.repo 字段全解释
# ← [id]:唯一,不能有空格/点/中文,不能和其他源重复
[mycompany-el9-custom]
# 名称,yum repolist 时显示
name=MyCompany EL9 Custom Packages
# 最重要:源的根 URL,下必须有 repodata/ 目录
# 支持 http:// https:// ftp:// file:///(本地源)
baseurl=http://10.0.0.100/el9/x86_64/custom
# 1=启用 0=禁用;关了就不参与安装/更新
enabled=1
# 1=检查 RPM 包 GPG 签名;0=不检查(内网可信源可以 0)
gpgcheck=1
# gpgcheck=1 时告诉客户端去哪拿公钥;支持 http://
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany
# 数字越小优先级越高(相同包多个源都有时,优先选小的)
priority=1
# 多 baseurl 时按顺序(优先级优先),另一选项 roundrobin
failovermethod=priority
# 失败重试 3 次
retries=3
# 单 HTTP 请求超时 30 秒
timeout=30
# 只缓存包体,不缓存元数据
http_caching=packages
# dnf 模块化源遇到冲突时优先热修复,别老冲突
module_hotfixes=1
# repodata 缓存 24h(内网可 7200,看你同步频率)
metadata_expire=86400
# 1=源挂了当没看见继续装;0=源挂直接报错(生产建议 0 防止误装错版本)
skip_if_unavailable=0
# 用 HTTPS + 自签证书时设 0,正经证书不建议关
sslverify=0
# Nginx Basic Auth 用户名(配合 baseurl https)
username=ops
password=Secret123!3.2 推荐内网模板:/etc/yum.repos.d/MyCompany-EL9.repo(直接复制)
# ———— 内网自建源 4 段:baseos / appstream / extras / custom ————
[mycompany-el9-baseos]
name=MyCompany $releasever - BaseOS
baseurl=http://10.0.0.100/$releasever/$basearch/baseos
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
priority=1
[mycompany-el9-appstream]
name=MyCompany $releasever - AppStream
baseurl=http://10.0.0.100/$releasever/$basearch/appstream
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
priority=1
[mycompany-el9-extras]
name=MyCompany $releasever - Extras
baseurl=http://10.0.0.100/$releasever/$basearch/extras
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9
priority=1
[mycompany-el9-custom]
name=MyCompany $releasever - Custom Business Packages
baseurl=http://10.0.0.100/$releasever/$basearch/custom
enabled=1
gpgcheck=0
priority=1模板里的
$releasever(客户端会自动替换成 9/8/7)和$basearch(自动替换 x86_64/aarch64)强烈建议用变量,不要硬写,一份 .repo 可以同时分发 el8 el9。
3.3 关公网源,强制只走内网(防漏公网)
新装好的机器默认有一堆 Rocky-.repo / CentOS-.repo,要关公网源,只保留内网那个:
# 方法 A(推荐,温柔):官方源 disable,保留回滚
dnf config-manager --set-disabled baseos appstream extras epel
# 查看状态:应该只剩 [mycompany-xxx] enabled=1
dnf repolist enabled
# 方法 B(暴力):直接把官方 repo 文件挪走备份
mkdir -p /etc/yum.repos.d/disabled
mv /etc/yum.repos.d/Rocky-*.repo /etc/yum.repos.d/disabled/ 2>/dev/null
mv /etc/yum.repos.d/CentOS-*.repo /etc/yum.repos.d/disabled/ 2>/dev/null3.4 客户端生效三板斧(任何时候改完 .repo 都跑一遍)
# 1) 清空缓存(旧的 repodata 就别用了)
dnf clean all
# 2) 重新生成缓存(顺便验证源可访问;任何一个源 404/GPG 失败都会报错暴露出来)
dnf makecache
# 3) 看你能装的包总数(对一下就是源里 rpm 数量级)
dnf list available --repo mycompany-el9-custom | wc -l
# 4) 装一个小的真测一次
dnf install -y --repo mycompany-el9-custom jq如果要指定只从内网源装,任何命令都加
--disablerepo="*" --enablerepo="mycompany-*":dnf install -y nginx --disablerepo="*" --enablerepo="mycompany-*"就绝对不会漏去公网。
五、进阶(按需打开):HTTPS + Basic Auth + 自己 GPG 签名
4.1 HTTPS + 用户名密码(源对公网发布时必开)
Nginx server {} 块里加:
listen 443 ssl http2;
ssl_certificate /etc/nginx/certs/yum-repo.pem;
ssl_certificate_key /etc/nginx/certs/yum-repo.key;
auth_basic "YUM Repo - Login";
auth_basic_user_file /etc/nginx/.htpasswd;客户端的 .repo 里 baseurl 写成 https://,并加 username/password 或直接嵌 URL:
baseurl=https://ops:YourStrongPassword@10.0.0.100/el9/$basearch/custom
sslverify=14.2 自己打签名(合规/企业发布自研 rpm)
# 生成 GPG 密钥(空密码,无交互)
cat > gen-key.txt <<'EOF'
%no-protection
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: MyCompany Release
Name-Email: release@infra.local
Expire-Date: 0
%commit
EOF
gpg --batch --gen-key gen-key.txt
# ★ 关键:告诉 rpm 用哪个 GPG key 签名(不加这步 rpm --addsign 会报错)
echo '%_gpg_name release@infra.local' > ~/.rpmmacros
# 导出公钥(分发给所有客户端 /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany)
gpg --export --armor release@infra.local > /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany
# 客户端导入
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany
# 源服务器发布 rpm 前签名
rpm --addsign /var/www/yum/el9/x86_64/custom/*.rpm
# 签名后重新 createrepo_c --update
createrepo_c --update /var/www/yum/el9/x86_64/custom
# 客户端 repo 里 gpgcheck=1 + gpgkey=file:///... 就能验签六、25 条常用 yum/dnf 命令速查(按使用频率分类,每条都带示例)
5.1 查(每天问最多的)
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 列出所有可装的包总数 | dnf list available | wc -l | |
| 搜索名字带 “nginx” 的包 | dnf search nginx / dnf search all nginx(all 连描述一起搜) | 搜索首选 |
| 看一个包的详细信息(版本/大小/源/简介) | dnf info nginx / dnf info --installed nginx(只看已装) | |
我想装 ifconfig,不知道在哪个包里 | dnf provides '*/ifconfig' / dnf whatprovides /usr/bin/top | 最常用的”找不到命令 → 找对应 rpm” |
| 列出一个 rpm 安装后的文件(会铺到哪) | rpm -ql nginx / dnf repoquery -l nginx(不装只查) | |
一个文件 /etc/nginx/nginx.conf 是哪个包装的 | rpm -qf /etc/nginx/nginx.conf / dnf whatprovides /etc/nginx/nginx.conf | |
| 一个包依赖哪些别的包 | dnf deplist nginx / dnf repoquery --requires --resolve nginx | 排查依赖冲突 |
| 列出当前所有源(启用+禁用) | dnf repolist all / dnf repoinfo baseos(单个详情) | |
| 查看一个包有哪些”模块流”版本(nodejs/postgresql 多版本) | dnf module list nodejs | AppStream 才有 |
| 列出所有安装过的包按时间排序 | rpm -qa --last | head -30 | 审计”昨天装了啥” |
| 检查一个包签名是否合法 | rpm -K /var/www/yum/.../custom/your.rpm |
5.2 装
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 装一个/多个包 | dnf install -y nginx keepalived redis | -y 免交互(脚本里必加) |
| 只下载不安装(拷到别的机器) | dnf download --resolve --alldeps --destdir=/tmp/dl nginx | 内网装机最常用 |
装一个本地 .rpm | dnf localinstall -y /tmp/xxx.rpm / rpm -ivh /tmp/xxx.rpm(rpm 不处理依赖) | dnf 会帮你解依赖 |
| 重装(误删配置文件想恢复) | dnf reinstall -y nginx | |
| 装一组 “Development Tools” 组包 | dnf groupinstall -y "Development Tools" / dnf group list 看所有组 | gcc/make/git 一键集齐 |
| 装一个模块流的指定版本(如 postgresql 15) | dnf module enable -y postgresql:15 && dnf install -y postgresql-server | AppStream 常用 |
| 从一个指定源装(怕公网源污染) | dnf install -y --disablerepo="*" --enablerepo="mycompany-el9-custom" myapp |
5.3 更
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 检查哪些包能更 | dnf check-update(不装,只列出) | 生产更前必跑 |
| 只更安全补丁(不更功能)⭐ 生产最爱 | dnf updateinfo summary → dnf update --security -y | |
| 全量更(所有包更到最新) | dnf update -y 等价 dnf upgrade | RHEL 8+ upgrade 和 update 同义 |
| 更到和源保持完全一致(多退少补,降级缺失包) | dnf distro-sync -y | 切源(从公网→内网)后必跑 |
| 只更一个包 | dnf update -y nginx | |
| 更新后需要重启吗? | dnf needs-restarting -r(告诉你需不需要 reboot)/ -s 看哪些服务要重启 | 安全补丁后常用 |
5.4 删 + 清缓存
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 删一个包 | dnf remove -y nginx | 会自动删它的没用依赖吗?不会,要 autoremove |
| 删孤儿依赖(之前作为依赖装进来、现在没人用了)⭐ | dnf autoremove -y | 定期跑,磁盘不涨 |
| 清 yum/dnf 本地缓存(源挂了想重拉元数据) | dnf clean all / dnf clean packages(只删 rpm) | + dnf makecache 一套组合 |
| 强制过期元数据,下次拉最新 | dnf clean expire-cache | 比 clean all 轻 |
| 看缓存目录多大 | du -sh /var/cache/dnf /var/cache/yum 2>/dev/null |
5.5 管源
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 临时禁用/启用一个源 | dnf config-manager --set-disabled epel / --set-enabled epel | 写进 repo 文件的 enabled=0/1 |
| 快速加一个新的公网源 | dnf config-manager --add-repo https://mirrors.tuna.tsinghua.edu.cn/epel/9/Everything/x86_64/ | 会自动生成一个临时 .repo |
| 只从某源更/装 | --disablerepo="*" --enablerepo="id"(组合任何子命令) | 任何 install/update/search 都能加 |
| 关闭最快镜像(避免随机选慢源) | echo "fastestmirror=0" >> /etc/dnf/dnf.conf | dnf 默认不启用 fastestmirror;若装了 dnf-plugin-fastestmirror 才需显式关 |
| 把源里所有包同步到本地 | reposync --repoid=baseos -p /tmp/baseos | 就是我们源服务器那个命令 |
5.6 排障 / 历史 / 调试
| 想做什么 | 命令 | 说明 |
|---|---|---|
| 查看安装/删除历史(谁在什么时候装了什么)⭐ | dnf history list / dnf history info 23 看第 23 次详情 | |
| 回滚第 23 笔操作(把那次装的包全卸) | dnf history undo 23 -y | 生产”手滑装错了”的救命指令 |
| 重做第 23 笔操作 | dnf history redo 23 -y | 批量克隆部署环境 |
| 依赖冲突/缺包时跑更详细的 debug | dnf -d 9 install -y nginx --showduplicates(-d 0~10 详细度 9 最细) | |
| 所有插件都禁用(怀疑插件 bug) | dnf install nginx --noplugins | |
| rpm 数据库坏了(rpmdb open failed) | rm -f /var/lib/rpm/__db.* ; rpm --rebuilddb | 老机器偶发 |
| 解不出依赖,要手动分析依赖图 | dnf depsolve nginx / dnf repoquery --tree --requires nginx | |
| 检查一个 rpm 有没有装过哪些脚本(安装前后执行了啥) | rpm -qp --scripts /tmp/xxx.rpm(未装)/ rpm -q --scripts nginx(已装) | 安全审计必看 |
七、7 个高频坑排障(遇到按序试)
❌ 1. No package nginx available. 明明源里有 rpm
排查顺序:
# ① 确认你放 rpm 的目录下真的生成 repodata/repomd.xml
ls /var/www/yum/el9/x86_64/custom/repodata/
# 没有 → createrepo_c /var/www/yum/el9/x86_64/custom
# ② 客户端能拉到 repomd.xml 吗
curl -I http://10.0.0.100/el9/x86_64/custom/repodata/repomd.xml
# 404 → Nginx root 写错(/var/www/yum 还是 /usr/share/nginx/html?)
# 403 → SELinux / Nginx 用户对目录没读权限 → restorecon + chown
# ③ 客户端这个源真的 enabled=1 吗
dnf repolist enabled | grep mycompany
# 没有 → enabled=0 → dnf config-manager --set-enabled mycompany-el9-custom
# ④ 清缓存 + 重新 makecache(缓存了旧的空索引)
dnf clean all && dnf makecache
# ⑤ 架构不匹配(放了 i686 装 x86_64?)
dnf repoquery --repo mycompany-el9-custom --arch x86_64 'nginx*'❌ 2. Error: Failed to download metadata for repo 'xxx': repomd.xml GPG signature check failed
源没签名/你要求 gpgcheck=1,两种解法:
# 简单内网(内网可信就关签名):对应 .repo 段改 gpgcheck=0
# 或者正确导入公钥
curl -o /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany http://10.0.0.100/keys/RPM-GPG-KEY-MyCompany
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany
# .repo 里指向它:gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany❌ 3. 客户端一直 Trying other mirror... 卡 30 秒才跳
RHEL/CentOS 默认源是 mirrorlist=(给一个镜像列表再动态挑一个),内网源里没有 mirrorlist 服务,就会一直超时重试。解法:把所有 .repo 里 mirrorlist=… 这行全部注释掉,baseurl= 保留写死的内网地址,并关 fastestmirror:
# 批量注释 mirrorlist
sed -i 's/^mirrorlist=/#mirrorlist=/' /etc/yum.repos.d/*.repo
# dnf 默认无 fastestmirror 插件,无需额外处理;如已安装则显式关闭
grep -q '^fastestmirror=' /etc/dnf/dnf.conf && sed -i 's/^fastestmirror=.*/fastestmirror=0/' /etc/dnf/dnf.conf || echo "fastestmirror=0" >> /etc/dnf/dnf.conf
dnf clean all && dnf makecache❌ 4. 明明服务器刚加了新包,客户端 dnf install 还是旧版
元数据没过期:
# 服务端:createrepo_c --update 必须跑
createrepo_c --update /var/www/yum/el9/x86_64/custom
# 客户端:强制忽略本地过期时间
dnf clean expire-cache
dnf install -y myapp --refresh
# 或者直接 dnf makecache timer 重置❌ 5. Error: rpmdb open failed / error: rpmdb: BDB0113
RPM 数据库坏了(直接 kill -9 yum 进程 / 断电常见):
rm -f /var/lib/rpm/__db.*
rpm --rebuilddb
# 之后 dnf clean all && dnf makecache❌ 6. 自研包明明签名了,客户端显示 Header V4 RSA/SHA256 Signature, key ID XXXXXXX: NOKEY
客户端没导入对应公钥:
rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-MyCompany
# 再验
rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n'❌ 7. All matches were filtered out by modular filtering
AppStream 模块化过滤了,说明你要装的包在某个 module stream 中,但默认 stream 不包含:
# 1. 看有哪些流可用
dnf module list postgresql
# 2. 启用你要的流
dnf module enable -y postgresql:15
# 3. 再装
dnf install -y postgresql-server结语
内网 yum 源看起来只是”起个 Nginx 放包”,真到生产能稳定跑 3 年,关键点其实就两个:
- 放 rpm 之后一定要
createrepo_c --update,然后curl一次repomd.xml确认服务端没问题,别扔锅给客户端; - 客户端 .repo 文件
baseurl要精确到”repodata 上一级目录”,并用$releasever/$basearch变量,别硬写死架构。
把上面两份模板(yum-repo-sync.sh + 客户端 MyCompany-EL9.repo)分发到自动化里(Ansible/Salt/云-init),所有机器装机后能立刻装内网业务包,整个部署链就闭环了。