⚠️ 提示:本站 AI 助手使用博主个人 API Token,没事别特么瞎用。
运维 · · 约 43 分钟阅读

YUM/DNF 软件源完全指南:自建内网 yum 源、客户端 .repo 配置、以及 25 个常用命令速查

一两台机器装软件用官方源没问题,到了几十台上百台统一装机、内网离线、要稳定可复现的部署环境时就该自建 yum 源了。本文从 0 开始用 createrepo_c + Nginx 搭一个支持增量更新、每天自动同步、几百台并发不卡的内网软件源,再讲客户端 .repo 文件每个字段怎么写、公网/内网源怎么切,最后把生产上最常用的 25 条 yum/dnf 命令按《查/装/更/删/源/排障》六类全部列好示例。

YUM/DNF 软件源完全指南:自建内网 yum 源、客户端 .repo 配置、以及 25 个常用命令速查

一两台测试机 yum install nginx 404 了,大不了 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/*.rpm

2.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 -20

2.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.target
systemctl 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/null

3.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=1

4.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 nodejsAppStream 才有
列出所有安装过的包按时间排序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内网装机最常用
装一个本地 .rpmdnf 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-serverAppStream 常用
从一个指定源装(怕公网源污染)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 upgradeRHEL 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.confdnf 默认不启用 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批量克隆部署环境
依赖冲突/缺包时跑更详细的 debugdnf -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 年,关键点其实就两个:

  1. 放 rpm 之后一定要 createrepo_c --update,然后 curl 一次 repomd.xml 确认服务端没问题,别扔锅给客户端;
  2. 客户端 .repo 文件 baseurl 要精确到”repodata 上一级目录”,并用 $releasever/$basearch 变量,别硬写死架构。

把上面两份模板(yum-repo-sync.sh + 客户端 MyCompany-EL9.repo)分发到自动化里(Ansible/Salt/云-init),所有机器装机后能立刻装内网业务包,整个部署链就闭环了。

问问 AI