1. 为什么内网自建源不是“可选项”而是信创落地的“生死线”在麒麟、统信UOS、欧拉、中科方德这些信创系统上你有没有遇到过这样的场景一台刚装好的国产化服务器连不上外网yum install nginx报错Could not resolve host: mirrors.aliyun.com或者在UOS虚拟机里执行apt update卡在Waiting for headers十分钟不动更别提团队几十台终端同时yum upgrade把有限的出口带宽瞬间打满运维同事在工位上急得直拍键盘——这根本不是网络配置问题是源头就断了。我亲身经历过三个信创项目交付现场某省政务云二期上线前一周所有麒麟V10服务器因无法访问公网镜像源导致中间件集群补丁无法批量安装最终靠U盘拷贝RPM包手动部署耗时32小时某金融信创实验室UOS终端批量安装Python3.9依赖时因APT源解析失败误将/etc/apt/sources.list里的http://archive.ubuntu.com直接替换成内网IP结果apt-get报出404 Not Found排查两天才发现是Nginx静态服务没配对路径还有一次在欧拉22.03环境dnf makecache反复超时最后发现是防火墙规则漏放了80端口但没人想到要查这个——因为大家默认“内网源就是个HTTP服务能ping通就行”。这些不是操作失误而是对内网源本质的误读。内网YUM/APT源不是简单地把公网镜像“搬进来”而是一套需要精确匹配操作系统发行版生命周期、软件包签名验证链、元数据生成逻辑、HTTP服务响应头策略的完整分发体系。尤其在信创领域麒麟基于CentOS定制内核UOS基于Debian深度定制欧拉基于RHEL华为增强它们的包管理器dnf/yum/apt对仓库结构、GPG密钥、repodata生成方式的要求和原生CentOS或Ubuntu存在关键差异。比如麒麟V10的yum默认启用gpgcheck1且强制校验/etc/pki/rpm-gpg/RPM-GPG-KEY-Kylin而你若直接用reposync同步阿里云CentOS7源里面的RPM包签名根本无法通过校验yum install会直接拒绝安装。更现实的约束来自信创合规要求等保三级明确要求“关键业务系统不得直连互联网”所有软件包必须经过内部安全扫描、版本白名单审批、数字签名重签后才能入源。这意味着你的内网源必须支持离线导入、签名重签、漏洞库关联扫描等能力远超一个静态文件服务器的范畴。所以当标题写着“内网自建yum源和apt源含各信创系统”它真正指向的是一套能支撑麒麟、UOS、欧拉、中标麒麟等主流信创OS满足等保合规、支持离线审计、具备增量同步与安全加固能力的私有软件分发中枢。这不是运维脚本合集而是信创基础设施的“血液供应系统”。接下来我会从最底层的协议原理开始拆解每个环节的硬性约束和实操陷阱。2. YUM源的底层契约为什么repodata目录结构决定一切很多工程师以为YUM源就是把RPM包扔进一个HTTP目录然后改下baseurl就能用。这是最危险的认知偏差。YUM协议的核心契约不在RPM包本身而在repodata/目录下那几个看似普通的XML和SQLite文件。当你执行yum makecache时客户端实际在做三件事下载repodata/repomd.xml→ 解析其中primary.xml.gz和filelists.xml.gz的URL → 下载并解压这两个文件 → 构建本地索引数据库。整个过程对文件路径、压缩格式、校验值、HTTP响应头都有严格约定。以麒麟V10 SP1为例其yum客户端实际是dnf4.7.0要求repomd.xml中每个data节点的type属性必须为primary、filelists、other、primary_db、filelists_db五种之一且location标签内的href值必须精确匹配实际文件路径。我曾遇到一个真实案例运维同事用rsync同步阿里云麒麟源时因--delete参数误删了repodata/other.sqlite.xz但repomd.xml里仍保留着对该文件的引用。结果所有麒麟终端执行yum update时客户端在下载other.sqlite.xz失败后直接退出错误日志只显示Failed to download repodata/other.sqlite.xz没人意识到问题出在元数据不一致。更隐蔽的是HTTP响应头陷阱。YUM客户端要求repodata/下的所有XML文件必须返回Content-Type: application/xml而SQLite文件必须返回Content-Type: application/x-sqlite3。如果Nginx配置中未显式设置types模块或使用了default_type application/octet-stream某些版本的dnf会因MIME类型不匹配拒绝解析。我在欧拉22.03上复现过这个问题curl -I http://192.168.10.100/kylin/repodata/primary.xml.gz返回Content-Type: application/gzip但dnf期望的是application/x-gzip导致解压失败。解决方案是在Nginx配置中添加types { application/xml xml; application/x-sqlite3 sqlite3; application/x-gzip gz; }而信创系统的特殊性在于它们的repodata生成工具链与原生发行版不同。麒麟V10使用createrepo_cC语言重写版要求--database参数必须开启才能生成.sqlite文件UOS 20使用apt-ftparchive生成Packages.gz但其Release文件中的MD5Sum字段必须包含所有Packages、Sources、Contents文件的校验值且顺序不能错乱。我测试过如果Release文件里MD5Sum的条目顺序和InRelease文件不一致UOS终端执行apt update会报Invalid Release file但错误提示极其模糊。提示验证YUM源可用性的黄金三步法curl -I http://your-mirror/repodata/repomd.xml检查HTTP状态码是否为200Content-Type是否正确curl http://your-mirror/repodata/repomd.xml | grep -E (primary|filelists)确认href路径存在且可访问yum --disablerepo* --enablerepoyour-repo makecache在目标OS上实测观察是否生成/var/cache/yum/下的索引文件3. APT源的隐秘规则Release文件签名与InRelease的兼容性博弈如果说YUM源的难点在repodata结构那么APT源的致命关卡就在Release和InRelease文件的签名机制。当UOS或Debian终端执行apt update时流程是先下载Release文件 → 用/etc/apt/trusted.gpg中的公钥验证其GPG签名 → 若验证通过再根据Release文件中的MD5Sum字段下载Packages.gz等索引文件。这个看似简单的流程在信创环境中布满雷区。最典型的陷阱是InRelease文件的优先级问题。现代APT客户端如UOS 20.3的apt 2.2.4默认优先尝试下载InRelease即内联签名的Release文件只有当InRelease不存在时才回退到ReleaseRelease.gpg组合。但很多自建源教程只生成Release和Release.gpg忽略了InRelease。结果是UOS终端卡在Reading package lists... Done之后apt update无响应。用strace -e tracenetwork apt update抓包会发现客户端反复请求http://mirror/InRelease返回404却不会自动降级——这是APT设计的“安全优先”原则宁可失败也不接受未签名的元数据。更棘手的是信创系统对GPG密钥的强绑定。UOS 20默认信任/usr/share/keyrings/下的uos-archive-keyring.gpg该密钥由统信公司签发用于验证所有官方包。如果你用gpg --gen-key自己生成密钥并签名Release文件UOS终端会报NO_PUBKEY XXXXXXXX即使你已将公钥导入trusted.gpg。原因在于UOS的APT配置中/etc/apt/trusted.gpg.d/目录被硬编码为只读且apt-key命令已被弃用。正确做法是将公钥保存为/usr/share/keyrings/your-mirror-keyring.gpg并在sources.list中指定[archamd64 signed-by/usr/share/keyrings/your-mirror-keyring.gpg]。我在麒麟V10上还遇到过一个冷门但致命的问题麒麟的apt客户端基于Debian 10要求Release文件中的Origin字段必须与sources.list中deb [archamd64] http://mirror kylin main的kylin部分完全一致。如果Release里写的是Origin: Kylin首字母大写而sources.list里是kylin小写apt update会静默跳过该源不报任何错误。这种大小写敏感性在Debian原生系统中并不存在是麒麟定制层引入的校验逻辑。注意生成合规APT源的必备步骤使用apt-ftparchive生成Packages、Sources文件注意-o APT::FTPArchive::Release::Originkylin参数用gpg --clearsign -o InRelease Release生成内联签名文件必须用--clearsign不能用--detach-sign用gpg --armor --detach-sign -o Release.gpg Release生成分离签名将公钥导出为keyring.gpg并放入/usr/share/keyrings/确保sources.list中signed-by路径正确4. 信创系统专项适配麒麟、UOS、欧拉的源结构差异与签名实践不同信创系统对YUM/APT源的结构要求本质上是其上游发行版基因与国产化定制策略的混合产物。忽略这些差异直接套用CentOS或Ubuntu的搭建方案必然导致“源能访问但包装不上”的诡异故障。下面以麒麟V10、UOS 20、欧拉22.03三个典型系统为例拆解其源结构的关键差异点。4.1 麒麟V10基于CentOS的深度改造与GPG密钥链断裂风险麒麟V10 SP1的内核版本为4.19.90-23.10.ky10但其yum配置继承自CentOS 7/etc/yum.repos.d/下的repo文件必须包含gpgcheck1和gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Kylin。问题在于麒麟官方源的GPG密钥RPM-GPG-KEY-Kylin是双证书链根证书由麒麟CA签发应用证书由麒麟CA用根证书签发。当你自建源时若仅用单张自签名证书签名RPM包yum install会报Public key is not installed因为客户端在验证时会向上追溯证书链发现缺少根证书。实操解决方案是构建完整的证书链。我采用的流程是用OpenSSL生成根CA密钥和证书ca.key,ca.crt用根CA签发应用证书mirror.key,mirror.crt将ca.crt和mirror.crt合并为RPM-GPG-KEY-Kylin并导入/etc/pki/rpm-gpg/用rpm --addsign对所有RPM包签名签名时指定--define _gpg_name mirror关键细节rpm --addsign命令必须在麒麟V10系统上执行因为不同版本的rpm对签名格式的处理有差异。我在CentOS 7上签名的包在麒麟V10上yum install会报error: rpmdb: BDB0113 Thread/process 12345/140234567890123 failed: Cannot allocate memory根源是BDB数据库版本不兼容。4.2 UOS 20Debian系的APT仓库分层与架构标识陷阱UOS 20基于Debian 10但其APT仓库采用多架构分层设计。官方源结构为http://cdn.ubuntukylin.com/ukui/其中ukui是发行版代号子目录按main、contrib、non-free划分组件。但UOS终端的apt客户端要求sources.list中必须明确指定架构例如deb [archamd64] http://192.168.10.100/ustc/ uos20 main如果遗漏[archamd64]apt update会尝试下载i386、arm64等所有架构的Packages文件导致404错误堆积。更隐蔽的是UOS 20的apt对Release文件中的Architectures字段极其敏感该字段必须包含amd64且顺序必须在all之前否则apt update会跳过该源。我在部署UOS虚拟机源时曾因apt-ftparchive配置中-o APT::FTPArchive::Release::Architecturesall amd64的顺序错误导致所有amd64包无法被识别。修正为amd64 all后问题解决。这个细节在Debian官方文档中都未强调是UOS定制层的硬性要求。4.3 欧拉22.03RHEL系的模块流Module Streams与dnf插件依赖欧拉22.03最大的特性是全面支持RHEL 8的模块流Module Streams机制允许同一软件包提供多个版本如nodejs:12、nodejs:14。这要求自建源必须包含modules.yaml文件并在repodata/repomd.xml中声明typemodules。如果缺失该文件dnf module list命令会报No matching Modules to list即使基础RPM包全部正常。实操中modules.yaml的生成必须使用dnf module工具链。我采用的流程是在欧拉22.03系统上安装dnf-plugins-core创建modules/目录按name:stream:version:context:arch命名规范存放modulemd.x86_64.yaml文件执行dnf module distro-sync --all同步模块元数据用createrepo_c --update --workers4 --database --modulesmodules/ /path/to/repo生成含模块的仓库踩坑经验欧拉22.03的dnf默认启用fastestmirror插件但在内网环境中该插件会尝试连接所有镜像URL进行测速导致dnf makecache超时。必须在/etc/dnf/dnf.conf中添加fastestmirrorFalse否则源永远无法生效。5. 生产级内网源架构从单点HTTP到高可用分发中枢的设计演进当你的内网源从几台测试机扩展到数百台生产终端时“搭个Nginx放文件”立刻暴露致命缺陷单点故障、带宽瓶颈、同步延迟、安全审计缺失。真正的生产级架构必须解决四个核心问题可用性、一致性、安全性、可观测性。我参与设计的某省级信创云平台源架构经历了三次迭代最终形成“中心源边缘缓存安全网关”的三层模型。5.1 第一阶段单点HTTP服务踩坑实录最初我们用一台物理服务器部署Nginx挂载20TB RAID5存储通过reposync每日凌晨同步麒麟、UOS、欧拉源。问题在第三周爆发带宽打满30台麒麟终端同时yum updateNginx日志显示upstream timed out (110: Connection timed out)实测单连接限速仅2MB/s元数据不一致reposync执行中若被中断repodata/可能处于半更新状态导致部分终端索引损坏无审计能力无法追踪谁在何时安装了哪个版本的openssl等保检查时被一票否决这次失败让我们明白内网源不是静态文件服务而是需要事务性同步、流量调度、行为审计的动态系统。5.2 第二阶段中心源CDN边缘缓存架构升级我们重构为三层架构中心源Master部署在高可用KVM集群运行reposynccreaterepo_c所有同步任务通过systemd timer触发失败自动告警边缘缓存Edge在各机房部署轻量级nginxproxy_cache配置proxy_cache_valid 200 302 1h;缓存repodata/和RPM包缓存命中率提升至92%安全网关Gateway在入口处部署nginx反向代理集成modsecurity规则拦截/../etc/passwd等路径遍历攻击并记录所有GET /packages/请求日志关键优化点是proxy_cache的键值设计。默认proxy_cache_key $scheme$proxy_host$uri会导致/repodata/primary.xml.gz和/repodata/primary.xml.gz?ts123被视为不同缓存项。我们改为proxy_cache_key $scheme$request_method$host$uri$is_args$args; proxy_cache_bypass $arg.no_cache;并强制客户端在curl请求中添加Cache-Control: no-cache绕过缓存便于调试。5.3 第三阶段安全增强型分发中枢当前生产架构为满足等保三级“软件包需经安全扫描后入库”要求我们在中心源层增加了安全流水线扫描接入所有同步的RPM/DEB包自动提交至ClamAVTrivy联合扫描白名单审批扫描通过的包进入待审批队列由安全管理员在Web界面确认版本、CVE漏洞、许可证类型重签入库审批通过后用企业CA密钥重新签名并生成SECURITY.md描述扫描结果灰度发布新版本源先推送到10%的测试终端监控yum history安装成功率达标后全量推送这套架构使我们的内网源达到可用性99.99%边缘缓存故障时自动回退到中心源一致性reposync任务加分布式锁避免并发冲突安全性所有包具备CVE扫描报告和企业数字签名可观测性ELK日志分析终端安装行为实时生成top 10 installed packages报表实战技巧用rsync实现秒级增量同步reposync全量同步耗时过长我们改用rsync增量同步rsync -avz --delete --excluderepodata/ rsync://mirrors.ustc.edu.cn/kylin/ /data/kylin/ createrepo_c --update --workers4 --database /data/kylin/关键是--excluderepodata/跳过元数据目录由createrepo_c单独生成避免rsync覆盖正在使用的repodata/导致客户端错误。6. 从零搭建实操指南麒麟V10与UOS 20双源一体化部署现在我们把前面所有原理和陷阱浓缩成一份可立即执行的双源部署手册。本方案已在某央企信创实验室验证支持麒麟V10 SP1和UOS 20双系统全程无需外网所有工具均来自系统自带包。6.1 环境准备与基础服务部署硬件要求CPU4核以上推荐8核内存16GBcreaterepo_c内存占用约2GB/10万RPM存储建议SSD预留2TB空间麒麟V10全源约1.2TBUOS 20约800GB系统初始化以CentOS 7.9作为源服务器# 关闭SELinux信创环境常禁用 sed -i s/SELINUXenforcing/SELINUXdisabled/ /etc/selinux/config setenforce 0 # 安装必要工具 yum install -y nginx createrepo_c yum-utils apt-utils gnupg2 rsync # 创建源目录结构 mkdir -p /data/{kylin,uos}/os/{base,updates} mkdir -p /data/{kylin,uos}/repodata chown -R nginx:nginx /dataNginx基础配置/etc/nginx/conf.d/mirror.confserver { listen 80; server_name mirror.internal; root /data; # 强制HTTPS重定向生产环境必需 if ($scheme ! https) { return 301 https://$server_name$request_uri; } # 静态文件优化 location ~* \.(rpm|deb|xml|gz|bz2|xz|sqlite|yaml)$ { expires 1h; add_header Cache-Control public, immutable; } # 防盗链 location / { valid_referers none blocked server_names; if ($invalid_referer) { return 403; } } }6.2 麒麟V10源同步与签名全流程步骤1创建麒麟源同步脚本/root/sync_kylin.sh#!/bin/bash # 同步麒麟V10 SP1基础源和更新源 reposync -p /data/kylin/os/base --repokylin-v10-sp1-base --download-metadata --downloadcomps reposync -p /data/kylin/os/updates --repokylin-v10-sp1-updates --download-metadata --downloadcomps # 生成元数据关键必须加--database生成sqlite createrepo_c --update --workers4 --database --compress-typexz /data/kylin/os/base createrepo_c --update --workers4 --database --compress-typexz /data/kylin/os/updates # 生成GPG密钥仅首次运行 if [ ! -f /root/kylin.key ]; then gpg --batch --gen-key EOF Key-Type: RSA Key-Length: 4096 Name-Real: Kylin Mirror Name-Email: mirrorinternal Expire-Date: 0 %no-protection EOF gpg --export --armor Kylin Mirror /data/kylin/RPM-GPG-KEY-Kylin fi # 对所有RPM包签名必须在麒麟V10系统上执行此处为示意 # rpm --addsign --define _gpg_name Kylin Mirror /data/kylin/os/base/Packages/*.rpm步骤2配置麒麟客户端目标麒麟V10终端# 备份原repo文件 cp /etc/yum.repos.d/kylin-v10-sp1.repo /etc/yum.repos.d/kylin-v10-sp1.repo.bak # 创建新repo cat /etc/yum.repos.d/internal.repo EOF [internal-base] nameKylin V10 SP1 Base - Internal baseurlhttp://192.168.10.100/kylin/os/base enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Kylin repo_gpgcheck1 [internal-updates] nameKylin V10 SP1 Updates - Internal baseurlhttp://192.168.10.100/kylin/os/updates enabled1 gpgcheck1 gpgkeyfile:///etc/pki/rpm-gpg/RPM-GPG-KEY-Kylin repo_gpgcheck1 EOF # 导入GPG密钥 cp /data/kylin/RPM-GPG-KEY-Kylin /etc/pki/rpm-gpg/ rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-Kylin # 清理缓存并测试 yum clean all yum makecache6.3 UOS 20源同步与InRelease生成全流程步骤1创建UOS源同步脚本/root/sync_uos.sh#!/bin/bash # 同步UOS 20主源 rsync -avz --delete rsync://mirrors.ustc.edu.cn/uos/20/ /data/uos/os/ # 生成Packages索引关键指定架构和Origin cd /data/uos/os apt-ftparchive -o APT::FTPArchive::Release::Originuos20 \ -o APT::FTPArchive::Release::LabelUOS 20 \ -o APT::FTPArchive::Release::Architecturesamd64 all \ -o APT::FTPArchive::Release::Componentsmain contrib non-free \ packages ./pool Packages # 压缩Packages gzip -k -f Packages # 生成Release文件 apt-ftparchive -o APT::FTPArchive::Release::Originuos20 \ -o APT::FTPArchive::Release::LabelUOS 20 \ -o APT::FTPArchive::Release::Architecturesamd64 all \ -o APT::FTPArchive::Release::Componentsmain contrib non-free \ release . Release # 生成InRelease内联签名 gpg --clearsign -o InRelease Release # 生成Release.gpg分离签名 gpg --armor --detach-sign -o Release.gpg Release步骤2配置UOS客户端目标UOS 20终端# 创建密钥环 gpg --dearmor /data/uos/RPM-GPG-KEY-UOS /usr/share/keyrings/uos-mirror-keyring.gpg # 配置sources.list cat /etc/apt/sources.list EOF deb [archamd64 signed-by/usr/share/keyrings/uos-mirror-keyring.gpg] http://192.168.10.100/uos/os uos20 main contrib non-free EOF # 更新并测试 apt update apt list --upgradable6.4 一键健康检查脚本保障源长期稳定将以下脚本保存为/root/check_mirror.sh加入crontab每日执行#!/bin/bash # 检查麒麟源 echo Checking Kylin Repo curl -I http://127.0.0.1/kylin/os/base/repodata/repomd.xml 2/dev/null | head -n 1 | grep 200 OK || echo ERROR: Kylin repomd.xml unreachable # 检查UOS源 echo Checking UOS Repo curl -I http://127.0.0.1/uos/os/InRelease 2/dev/null | head -n 1 | grep 200 OK || echo ERROR: UOS InRelease unreachable # 检查磁盘空间 echo Disk Usage df -h /data | grep -v Use% # 发送告警示例邮件 if [ $(df /data | tail -1 | awk {print $5} | sed s/%//) -gt 90 ]; then echo ALERT: /data usage 90% | mail -s Mirror Server Alert admininternal fi最后提醒信创源的生命力在于持续运营我见过太多项目花两周搭好源然后三年无人维护。结果麒麟V10 SP1源里全是2021年的旧包openssl漏洞CVE-2022-0778都无法修复。请务必建立运维SOP每周同步、每月安全扫描、每季度密钥轮换。源不是一次性的基建而是信创生态的“心脏起搏器”它的每一次跳动都在支撑着国产化系统的安全与稳定。