Yum 源服务器 运维手册(日常运维篇)

1. 系统简介

Yum 源服务器为企业内网 Linux 服务器提供 RPM 包分发服务,部署在 Linux 服务器上(通常使用 CentOS/Rocky/AlmaLinux),通过 HTTP/HTTPS 对外提供仓库访问。支持多发行版多版本仓库托管、增量同步上游镜像、GPG 签名验证。是企业 Linux 标准化运维的基础设施组件。

2. 账号维护

2.1 系统账号管理

# 创建运维专用账号
useradd -m -s /bin/bash repo_admin
passwd repo_admin

# 授予 sudo 权限(限定特定命令)
echo "repo_admin ALL=(ALL) NOPASSWD: /usr/bin/createrepo, /usr/bin/reposync, /usr/bin/rsync, /bin/systemctl restart httpd" > /etc/sudoers.d/repo_admin

# 检查账号
id repo_admin
sudo -l -U repo_admin

2.2 SSH 密钥管理

# 生成部署用密钥对(在管理端执行)
ssh-keygen -t ed25519 -f ~/.ssh/repo_deploy_key -C "repo-deploy@domain"

# 将公钥添加到 Yum 源服务器
ssh-copy-id -i ~/.ssh/repo_deploy_key.pub repo_admin@yum-server

# 禁用密码登录(安全加固)
sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
systemctl restart sshd

2.3 SELinux 管理

# 查看 SELinux 状态
getenforce

# 【推荐】保持 Enforcing,为仓库目录设置正确上下文
# 查看当前上下文
ls -Z /var/www/html/repo/

# 设置正确的 SELinux 上下文(HTTP 可读)
semanage fcontext -a -t httpd_sys_content_t "/var/www/html/repo(/.*)?"
restorecon -Rv /var/www/html/repo/

# 如果使用自定义端口,还需配置 SELinux 策略
semanage port -a -t http_port_t -p tcp 8080

2.4 防火墙规则管理

# HTTP 仓库(使用 firewalld)
firewall-cmd --permanent --add-service=http
firewall-cmd --reload

# HTTPS 仓库
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

# 自定义端口
firewall-cmd --permanent --add-port=8080/tcp
firewall-cmd --reload

# 验证防火墙规则
firewall-cmd --list-all

2.5 账号审计

# 查看所有系统用户
cat /etc/passwd | grep -E "home|bash"

# 查看 sudo 授权用户
cat /etc/sudoers /etc/sudoers.d/*

# 查看 SSH 登录记录
lastlog
last | head -30

# 查看最近登录失败的 IP
lastb | head -20
  • 每季度审核一次系统账号
  • 离职人员立即禁用或删除账号:usermod -L 用户名

3. 日常配置调整

3.1 仓库添加/删除/修改

创建新仓库

# 1. 创建目录结构
mkdir -p /var/www/html/repo/centos/7/os/x86_64
mkdir -p /var/www/html/repo/centos/7/updates/x86_64

# 2. 下载或复制 RPM 包到目录
# (详见 3.2 同步源配置)

# 3. 创建元数据(核心步骤)
createrepo --database /var/www/html/repo/centos/7/os/x86_64

# 4. 更新元数据(增量添加新包后)
createrepo --update /var/www/html/repo/centos/7/os/x86_64

# 5. 验证元数据
ls -la /var/www/html/repo/centos/7/os/x86_64/repodata/

删除仓库

# 直接删除目录
rm -rf /var/www/html/repo/centos/7/os

# 或在 nginx/apache 配置中注释掉对应 location

修改仓库配置(repomd.xml)

# repomd.xml 由 createrepo 自动生成,通常不需要手动修改
# 如需修改仓库描述显示
createrepo --update --pretty --simple-md-filenames /path/to/repo

# 查看 repomd.xml 内容
cat /var/www/html/repo/centos/7/os/x86_64/repodata/repomd.xml | head -20

3.2 同步源配置(上游 Mirror)

使用 reposync 同步

# 安装必要工具
yum install -y yum-utils createrepo

# 同步 CentOS 7 Base 仓库到本地
reposync --repoid=base --newest-only --download-metadata --download_path=/var/www/html/repo/centos/7/

# 同步只保留最新包(推荐,节省空间)
reposync --repoid=base --newest-only --download-metadata --download_path=/var/www/html/repo/centos/7/

# 同步后必须重新生成元数据
createrepo --update /var/www/html/repo/centos/7/os/x86_64/

使用 rsync 同步(更快,适合大型仓库)

# 从阿里云镜像站 rsync 同步 CentOS 7
rsync -avz --delete --exclude="i386" --exclude="debug" \
  rsync://mirrors.aliyun.com/centos/7/os/x86_64/ \
  /var/www/html/repo/centos/7/os/x86_64/

# 同步 EPEL 仓库
rsync -avz --delete --exclude="i386" --exclude="debug" \
  rsync://mirrors.aliyun.com/epel/7/x86_64/ \
  /var/www/html/repo/epel/7/x86_64/

3.3 同步频率配置(crontab)

配置定时同步任务

# 编辑 crontab
crontab -e -u repo_admin

# 添加同步任务(推荐每天凌晨同步)
# 每天凌晨 3:00 同步 Base 仓库
0 3 * * * /usr/local/bin/sync_repo.sh base > /var/log/repo_sync/base.log 2>&1

# 每天凌晨 4:00 同步 Updates 仓库
0 4 * * * /usr/local/bin/sync_repo.sh updates > /var/log/repo_sync/updates.log 2>&1

# 每周日凌晨 5:00 同步 EPEL 仓库
0 5 * * 0 /usr/local/bin/sync_repo.sh epel > /var/log/repo_sync/epel.log 2>&1

同步脚本示例(/usr/local/bin/sync_repo.sh)

#!/bin/bash
# sync_repo.sh - Yum 仓库同步脚本
REPO_NAME=$1
REPO_BASE="/var/www/html/repo"
LOG_FILE="/var/log/repo_sync/${REPO_NAME}.log"

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting sync for $REPO_NAME" >> $LOG_FILE

case $REPO_NAME in
  base)
    reposync --repoid=base --newest-only --download-metadata \
      --download_path=${REPO_BASE}/centos/7/ >> $LOG_FILE 2>&1
    createrepo --update ${REPO_BASE}/centos/7/os/x86_64/ >> $LOG_FILE 2>&1
    ;;
  updates)
    reposync --repoid=updates --newest-only --download-metadata \
      --download_path=${REPO_BASE}/centos/7/ >> $LOG_FILE 2>&1
    createrepo --update ${REPO_BASE}/centos/7/updates/x86_64/ >> $LOG_FILE 2>&1
    ;;
  epel)
    rsync -avz --delete --exclude="i386" --exclude="debug" \
      rsync://mirrors.aliyun.com/epel/7/x86_64/ \
      ${REPO_BASE}/epel/7/x86_64/ >> $LOG_FILE 2>&1
    createrepo --update ${REPO_BASE}/epel/7/x86_64/ >> $LOG_FILE 2>&1
    ;;
  *)
    echo "Usage: $0 {base|updates|epel}" >> $LOG_FILE
    exit 1
    ;;
esac

echo "[$(date '+%Y-%m-%d %H:%M:%S')] Sync completed for $REPO_NAME" >> $LOG_FILE

3.4 GPG 密钥管理

# 导入上游 GPG 密钥
rpm --import https://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

# 查看已导入的 GPG 密钥
rpm -qa gpg-pubkey*

# 导出 GPG 密钥供客户端使用
gpg --export -a "CentOS-7" > /var/www/html/repo/centos/RPM-GPG-KEY-CentOS-7

# 为本地仓库创建签名(可选,企业私有仓库需要)
gpg --gen-key   # 生成签名密钥
rpmsign --addsign --key-id=YOUR_KEY_ID /var/www/html/repo/local/*.rpm

3.5 客户端 repo 文件模板

# 保存到 /var/www/html/repo/client-templates/centos7.repo

# 供客户端使用的 repo 模板文件
[local-base]
name=CentOS-$releasever - Base (Local)
baseurl=http://yum-server.domain.com/centos/$releasever/os/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://yum-server.domain.com/centos/RPM-GPG-KEY-CentOS-$releasever

[local-updates]
name=CentOS-$releasever - Updates (Local)
baseurl=http://yum-server.domain.com/centos/$releasever/updates/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://yum-server.domain.com/centos/RPM-GPG-KEY-CentOS-$releasever

[local-epel]
name=EPEL for CentOS-$releasever (Local)
baseurl=http://yum-server.domain.com/epel/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=http://yum-server.domain.com/epel/RPM-GPG-KEY-EPEL-$releasever

3.6 Nginx/Apache 虚拟主机配置

Nginx 配置(推荐)

# /etc/nginx/conf.d/yum-repo.conf
server {
    listen       80;
    server_name  yum-server.domain.com;
    root         /var/www/html/repo;

    # 日志配置
    access_log  /var/log/nginx/yum-repo-access.log main;
    error_log   /var/log/nginx/yum-repo-error.log;

    # 启用目录列表
    autoindex on;
    autoindex_exact_size off;
    autoindex_localtime on;

    # 禁掉 debug 目录(不需要同步给客户端)
    location ~ /debug/ {
        deny all;
    }

    # 大文件下载优化
    location ~* \.(rpm)$ {
        sendfile on;
        tcp_nopush on;
    }
}

Apache 配置(备选)

# /etc/httpd/conf.d/yum-repo.conf
<VirtualHost *:80>
    ServerName yum-server.domain.com
    DocumentRoot /var/www/html/repo

    <Directory /var/www/html/repo>
        Options +Indexes +FollowSymLinks
        IndexOptions FancyIndexing NameWidth=* VersionSort
        Require all granted
    </Directory>

    # 访问日志
    CustomLog /var/log/httpd/yum-repo-access.log combined
    ErrorLog /var/log/httpd/yum-repo-error.log
</VirtualHost>

3.7 目录权限管理

# 设置目录拥有者
chown -R repo_admin:repo_admin /var/www/html/repo/

# 设置目录权限(755:目录可读可执行,文件644)
find /var/www/html/repo -type d -exec chmod 755 {} \;
find /var/www/html/repo -type f -exec chmod 644 {} \;

# 给 createrepo 写的数据库特殊权限
chmod 644 /var/www/html/repo/*/repodata/*

3.8 带宽限制(rsync --bwlimit)

# 同步时限制带宽,避免占满出口(限速 10MB/s = 10240 KB/s)
rsync -avz --delete --bwlimit=10240 \
  rsync://mirrors.aliyun.com/centos/7/os/x86_64/ \
  /var/www/html/repo/centos/7/os/x86_64/

# reposync 本身不支持带宽限制,可通过 rsync 替代

3.9 配置备份

backup_date=$(date +%Y%m%d)
mkdir -p /root/repo_backup/$backup_date

# 备份 Nginx/Apache 配置
cp /etc/nginx/conf.d/yum-repo.conf /root/repo_backup/$backup_date/
# 或
# cp /etc/httpd/conf.d/yum-repo.conf /root/repo_backup/$backup_date/

# 备份同步脚本
cp /usr/local/bin/sync_repo.sh /root/repo_backup/$backup_date/

# 备份 crontab
crontab -l > /root/repo_backup/$backup_date/crontab.txt

# 备份 GPG 密钥
gpg --export -a "密钥名" > /root/repo_backup/$backup_date/gpg-public.key
gpg --export-secret-keys -a "密钥名" > /root/repo_backup/$backup_date/gpg-private.key

# 备份客户端 repo 模板
cp /var/www/html/repo/client-templates/*.repo /root/repo_backup/$backup_date/

3.10 配置生效

  • Nginx 配置修改后重载:nginx -t && systemctl reload nginx
  • Apache 配置修改后重载:httpd -t && systemctl reload httpd
  • 仓库元数据更新(createrepo)后立即生效,无需重启服务
  • crontab 编辑后立即生效

4. 日常巡检 Checklist

检查项检查方法正常状态频率
Web 服务状态systemctl status nginxsystemctl status httpdactive (running)每日
仓库总磁盘空间df -h /var/www/html/repo使用率 < 80%每日
最近同步时间tail -3 /var/log/repo_sync/base.log最近24小时内有成功记录每日
仓库元数据完整性ls -la /var/www/html/repo/centos/7/os/x86_64/repodata/repomd.xml文件存在且最近修改时间与同步一致每日
客户端访问测试找一台客户端执行 yum repolist显示本地仓库且计数正确每日
HTTP 响应正常curl -s -o /dev/null -w "%{http_code}" http://localhost/repo/200 或 301每日
目录列表可访问`curl -s http://localhost/repo/centos/7/os/x86_64/ \grep "repodata"`返回目录列表每日
Nginx/Apache 错误日志tail -20 /var/log/nginx/yum-repo-error.log无大量 4xx/5xx 错误每日
repo 文件语法检查createrepo --check /var/www/html/repo/centos/7/os/x86_64/无错误输出每周
同步日志无报错`grep -i "error\fail" /var/log/repo_sync/*.log`无匹配每日
SELinux 状态getenforceEnforcing(推荐)每周
防火墙规则firewall-cmd --list-allhttp/https 服务已允许每周
存储空间预测`du -sh /var/www/html/repo/*/ \sort -rh`监控增长趋势每周

5. 系统启停操作

5.1 正常启动

# Nginx
systemctl start nginx
systemctl status nginx

# Apache
systemctl start httpd
systemctl status httpd

5.2 正常停止

# 先确认是否正在进行同步任务
ps aux | grep -E "rsync|reposync|createrepo"

# 停止 Web 服务
systemctl stop nginx
# 或
systemctl stop httpd

5.3 服务状态检查

# Web 服务
systemctl status nginx --no-pager

# 端口监听
ss -tlnp | grep -E ":80|:443"

# 仓库可访问性
curl -I http://localhost/repo/

5.4 异常处理

  • 端口冲突:ss -tlnp | grep :80 查看 80 端口占用
  • 进程卡住:killall -9 reposync 强制终止同步进程
  • 磁盘满了时先清理最早的仓库备份

6. 日志查看与分析

6.1 日志路径

# Web 服务日志
/var/log/nginx/yum-repo-access.log    # Nginx 访问日志
/var/log/nginx/yum-repo-error.log     # Nginx 错误日志
/var/log/httpd/yum-repo-access.log    # Apache 访问日志
/var/log/httpd/yum-repo-error.log     # Apache 错误日志

# 同步日志
/var/log/repo_sync/base.log           # Base 仓库同步日志
/var/log/repo_sync/updates.log        # Updates 同步日志
/var/log/repo_sync/epel.log           # EPEL 同步日志

# 系统日志
/var/log/messages                     # 系统消息
/var/log/cron                         # crontab 执行日志

6.2 关键日志关键字

日志/关键字含义处理
"error: Cannot retrieve repository metadata"仓库元数据损坏重新运行 createrepo
"No such file or directory: repodata"缺少元数据运行 createrepo
"Disk quota exceeded" / "No space left on device"磁盘空间满清理旧包或扩容
rsync error: timeout同步超时检查上游镜像可达性
"Permission denied" / 403权限错误检查目录权限和 SELinux
"404 Not Found"文件不存在检查仓库同步是否完整
"Connection refused"Web 服务未启动启动 nginx/httpd
"gpgkey retrieval failed"GPG 密钥下载失败检查 GPG 文件路径
"Delta RPMs disabled"增量 RPM 下载失败可忽略,自动回退下载完整包

6.3 日志轮转/清理

# 配置 logrotate 管理同步日志
cat > /etc/logrotate.d/repo-sync << 'EOF'
/var/log/repo_sync/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 644 repo_admin repo_admin
}
EOF

# 立即测试
logrotate -d /etc/logrotate.d/repo-sync

7. 常见故障处理

7.1 客户端 yum repolist 失败

现象:客户端执行 yum repolist 报错,显示仓库不可用

解决

# 在客户端上排查
# 1. 测试仓库 URL 可访问
curl -I http://yum-server.domain.com/repo/centos/7/os/x86_64/

# 2. 检查 repodata 是否存在
curl -s http://yum-server.domain.com/repo/centos/7/os/x86_64/repodata/repomd.xml | head -5

# 3. 检查客户端 DNS 解析
nslookup yum-server.domain.com

# 4. 如果 curl 正常但 yum 失败,检查 repo 文件
cat /etc/yum.repos.d/local.repo
# 确认 baseurl 路径正确,no proxy 设置不被代理拦截

# 5. 在服务器端检查访问日志
tail -20 /var/log/nginx/yum-repo-access.log | grep 客户端IP

7.2 同步失败(上游不可达)

现象:同步脚本报错,上游镜像无法连接

解决

# 1. 测试上游镜像连通性
curl -I rsync://mirrors.aliyun.com/
curl -I https://mirrors.aliyun.com/

# 2. 检查 DNS
nslookup mirrors.aliyun.com

# 3. 切换备用上游镜像
# 阿里云:rsync://mirrors.aliyun.com/
# 华为云:rsync://mirrors.huaweicloud.com/
# 清华:rsync://mirrors.tuna.tsinghua.edu.cn/

# 4. 如果所有外部源都不可达,临时挂起同步
crontab -e -u repo_admin
# 注释掉同步任务,系统管理员修复网络后再取消注释

# 5. 同步超时处理
# 增加 rsync 超时时间
rsync -avz --delete --timeout=3600 --bwlimit=10240 \
  rsync://mirrors.aliyun.com/centos/7/os/x86_64/ \
  /var/www/html/repo/centos/7/os/x86_64/

7.3 仓库元数据损坏

现象:客户端报 "Cannot retrieve repository metadata"

解决

# 1. 检查 repodata 目录
ls -la /var/www/html/repo/centos/7/os/x86_64/repodata/

# 2. 如果目录为空或不完整,重新生成元数据
createrepo --database /var/www/html/repo/centos/7/os/x86_64/

# 3. 如果仍有问题,清理后重新生成
rm -rf /var/www/html/repo/centos/7/os/x86_64/repodata/
createrepo --database /var/www/html/repo/centos/7/os/x86_64/

# 4. 验证
ls -la /var/www/html/repo/centos/7/os/x86_64/repodata/

7.4 磁盘空间满

现象:df -h 显示磁盘使用率 100%,同步失败

解决

# 1. 紧急释放空间:查看各仓库大小
du -sh /var/www/html/repo/*/

# 2. 清理不再需要的旧版本仓库
rm -rf /var/www/html/repo/centos/6/   # 如果已不再使用 CentOS 6

# 3. 清理 debug/debuginfo 包(通常不需要)
find /var/www/html/repo -path "*/debug/*" -delete

# 4. 清理临时文件和日志
rm -rf /tmp/reposync-*
rm -f /var/log/repo_sync/*.log-????????   # 清理旧日志
> /var/log/nginx/yum-repo-access.log      # 清空访问日志

# 5. 如果是 rsync 同步,立即停止当前占用磁盘的同步
pkill -9 rsync
pkill -9 reposync

# 6. 长期方案:添加磁盘或清理同步策略
# 修改同步脚本,只同步最新包(--newest-only)

7.5 SELinux 导致访问 403

现象:curl 访问返回 403 Forbidden

解决

# 1. 查看 SELinux 审计日志
ausearch -m avc -ts recent

# 2. 临时测试(关闭 SELinux)
setenforce 0
curl -I http://localhost/repo/   # 如果恢复正常,确认是 SELinux 问题

# 3. 恢复并修正 SELinux 上下文(不要长期关闭 SELinux)
setenforce 1
semanage fcontext -a -t httpd_sys_content_t "/var/www/html/repo(/.*)?"
restorecon -Rv /var/www/html/repo/

# 4. 验证
curl -I http://localhost/repo/

7.6 同步脚本不执行(crontab)

现象:发现仓库很久没更新,crontab 没执行

解决

# 1. 检查 crontab 服务
systemctl status crond

# 2. 检查 crontab 内容
crontab -l -u repo_admin

# 3. 检查 cron 日志
grep "sync_repo" /var/log/cron

# 4. 手动执行测试
su - repo_admin -c "/usr/local/bin/sync_repo.sh base"

# 5. 常见问题:
# - 脚本没有执行权限
chmod +x /usr/local/bin/sync_repo.sh

# - 脚本中使用了相对路径,需改为绝对路径
# - crontab 环境变量与交互式 shell 不同,脚本中 PATH 需要写完整

8. 备份与恢复

8.1 配置备份(元数据+配置文件)

backup_date=$(date +%Y%m%d_%H%M)
mkdir -p /backup/yum-repo/$backup_date

# 备份 Web 配置文件
tar czf /backup/yum-repo/$backup_date/nginx_conf.tar.gz /etc/nginx/conf.d/yum-repo.conf

# 备份同步脚本和 crontab
tar czf /backup/yum-repo/$backup_date/scripts.tar.gz /usr/local/bin/sync_repo.sh
crontab -l > /backup/yum-repo/$backup_date/crontab.txt

# 备份 GPG 密钥
gpg --export -a "密钥名" > /backup/yum-repo/$backup_date/gpg-public.key
gpg --export-secret-keys -a "密钥名" > /backup/yum-repo/$backup_date/gpg-private.key

# 备份仓库列表
find /var/www/html/repo -name repomd.xml | sed 's|/repodata/repomd.xml||' > /backup/yum-repo/$backup_date/repo_list.txt

echo "Backup completed: /backup/yum-repo/$backup_date"

8.2 完整恢复

# 1. 安装 Web 服务
yum install -y nginx createrepo yum-utils

# 2. 恢复配置文件
tar xzf /backup/yum-repo/20260630/nginx_conf.tar.gz -C /
nginx -t && systemctl restart nginx

# 3. 恢复 GPG 密钥
gpg --import /backup/yum-repo/20260630/gpg-private.key

# 4. 恢复同步脚本
cp /backup/yum-repo/20260630/scripts.tar.gz /tmp/
tar xzf /tmp/scripts.tar.gz -C /
chmod +x /usr/local/bin/sync_repo.sh

# 5. 恢复 crontab
crontab /backup/yum-repo/20260630/crontab.txt

# 6. 重新同步仓库(如没有 RPM 包备份,需要重新同步)
/usr/local/bin/sync_repo.sh base

# 7. 恢复仓库目录权限
chown -R root:root /var/www/html/repo/
restorecon -Rv /var/www/html/repo/

# 8. 验证
yum repolist

8.3 RPM 包增量备份(按需)

# 如果需要备份实际 RPM 包(数据量大,按需执行)
# 使用 rsync 备份到远程备份服务器
rsync -avz --delete /var/www/html/repo/ backup-server:/backup/yum-repo/