
简介面向国产麒麟及CentOS系统运维场景此离线升级包聚焦OpenSSH安全组件的版本迭代解决无互联网环境下远程连接服务的升级难题。资源仅含4个文件由3个gz压缩包和1个sh脚本构成gz包分别携带OpenSSL、OpenSSH、zlib的源代码覆盖底层加密库、SSH服务与压缩依赖sh脚本则自动完成解压、补丁、编译与安装还封装了常见参数和配置项全程无需联网即可执行。对于内网隔离、安全加固或批量部署需求能有效降低手动处理依赖和编译出错的风险。压缩包整体约20.04MB已有2090人次浏览或下载。使用后可获得较新版本OpenSSL与OpenSSH的关键安全补丁、zlib兼容配套以及可直接复用的自动化升级脚本相比逐一下载依赖再逐台编译流程更简洁整体包体紧凑、便于归档特别适合需要快速完成多主机远程管理链路升级的系统管理员与安全运维人员。1. 麒麟系统离线升级 OpenSSH为什么一键脚本比手工操作更靠谱如果你在政务或生产内网维护过国产麒麟操作系统大概率遇到过这种场景漏洞扫描报告亮红灯OpenSSH 版本过低要求限期修复。麻烦的是这台机器物理隔离yum 源根本连不上源码编译需要的依赖包还得靠 U 盘一个个拷进去更让人头皮发麻的是很多运维兄弟在这条路上翻过车——编译到一半报错、升级完 sshd 起不来、SELinux 拦截导致远程连接直接断掉。这套「国产麒麟操作系统离线一键升级 OpenSSH 版本及相关文件」就是干这个事的它把源码包、依赖 RPM、配置保留逻辑和回退方案打包成一个可复现的流程让离线环境下的 OpenSSH 升级从玄学变成标准化操作。适合负责国产化服务器运维、等保整改、内网漏洞修复的工程师尤其是刚接手麒麟环境、对 RPM 依赖树还不熟的新手。2. 升级前准备版本、依赖与备份三板斧2.1 先摸清现状当前版本与发行版的对应关系不同版本的麒麟操作系统包管理器和基础库差异很大。我这边接触最多的是麒麟 V10 服务器版基于 CentOS 8 系构建内核 4.19.90架构多为 x86_64 或 aarch64。升级前必须确认两件事当前 OpenSSH 版本号以及系统是哪个发行版基线。命令很简单cat /etc/kylin-release ssh -V 21 rpm -qa | grep -iE openssh|openssl|zlib|pam uname -m输出示例Kylin Linux Advanced Server V10 (SP2) /Tercel OpenSSH_8.2p1, OpenSSL 1.1.1f 6 Mar 2020 openssh-8.2p1-4.p01.ky10.x86_64 openssl-1.1.1f-4.p01.ky10.x86_64第一行告诉我们系统是麒麟 V10 SP2第二行确认当前 SSH 版本是 8.2p1第三行表明 OpenSSH 是通过 RPM 安装的。这里有个关键判断如果系统里 OpenSSH 是 RPM 包安装的升级时就有两条路线——要么找麒麟官方仓库的更新 RPM 做离线升级要么走源码编译安装覆盖二进制的路线。多数内网环境拿不到官方更新包所以才会有「一键升级脚本」这类资源的需求。确认架构也很重要。x86_64 和 aarch64 的依赖包不通用下载源码包时架构没关系但如果是准备 RPM 依赖包架构必须严格对应。提醒一下uname -m输出是 aarch64 的机器一定不要拷 x86_64 的 RPM 进去否则 rpm 安装阶段会直接报「wrong architecture」。2.2 离线依赖包清单编译 OpenSSH 到底需要什么源码编译 OpenSSH 并不复杂但依赖链是大部分新手卡住的地方。OpenSSH 编译需要 OpenSSL 开发库、Zlib 开发库、PAM 开发库以及基础工具链。在离线环境下这些依赖包必须提前在能联网的机器上用 yum 下载好再拷过去。我一般会用yumdownloader或repotrack把依赖连同子依赖全部拉下来避免缺包的尴尬。# 在联网的相同发行版机器上执行麒麟 V10 / CentOS 8 系 mkdir -p /tmp/ssh-deps repotrack --archx86_64 --destdir/tmp/ssh-deps \ gcc make perl zlib-devel openssl-devel pam-devel \ rpm-build glibc-devel krb5-devel参数说明repotrack会把指定包的全部依赖递归下载到 destdir这比yumdownloader更保险因为yumdownloader默认只下载指定包本身依赖缺失时离线安装照样会卡住。--arch限定架构防止多架构混入。如果系统里的 dnf 可用用dnf download --resolve效果一样。拿到依赖包后先在一台测试机上验证能正常离线安装rpm -Uvh /tmp/ssh-deps/*.rpm --test--test参数只做依赖检查不实际安装。这一步能提前暴露依赖冲突或缺少子依赖的问题比拷到生产机上再踩坑强得多。测试机上验证通过再打包上传到内网目标机放到固定目录比如/opt/ssh-update-bundle/。2.3 备份不是可选项升级前必须做的三件事我见过太多人跳过备份直接升级结果 SSH 挂了只能让机房同事插显示器救场。升级前的备份操作要覆盖配置、二进制和应急通道三个层面。配置备份最容易理解但最容易被忽略细节——不仅/etc/ssh/下的 sshd_config 要备份/etc/pam.d/sshd也要备份因为新版 OpenSSH 在make install时可能会覆盖或新增 PAM 配置。mkdir -p /opt/ssh-backup/etc /opt/ssh-backup/bin /opt/ssh-backup/lib cp -a /etc/ssh /opt/ssh-backup/etc/ssh cp -a /etc/pam.d/sshd /opt/ssh-backup/etc/pam.d-sshd.bak cp -a /usr/sbin/sshd /usr/bin/ssh /opt/ssh-backup/bin/ cp -a /usr/lib64/libcrypto.so* /opt/ssh-backup/lib/ 2/dev/null || true备份完成后我强烈建议你先检查带外管理通道是否可用——也就是 IPMI、BMC 或者物理控制台。如果这台机器没有任何带外管理手段升级过程中 SSH 断掉就真的回天乏术了。最稳妥的做法是把 SSH 服务器端口临时改成 2222 并保持当前会话不断这样就算 sshd 重启失败你还能通过现有连接把问题修回来。这个操作可以在升级脚本里做成一个开关参数。3. 一键升级脚本从源码编译到安全切换服务3.1 脚本主流程为什么先编译后切换我的设计思路是脚本不做原地覆盖而是先把新版本编译安装到一个临时前缀目录如/usr/local/openssh-9.8p1然后手动把二进制复制到系统目录。为什么不直接./configure --prefix/usr然后make install因为在生产环境运行make install会直接覆盖正在运行的 sshd 二进制和配置文件一旦编译出的二进制有兼容性问题当前连接可能瞬间断掉而且没有后悔药。正确的流程是编译完成 → 备份当前配置 → 复制新二进制到/usr/sbin/和/usr/bin/→ 同步密钥和配置文件 → 重载 systemd 服务 → 保留当前 SSH 连接并验证新连接可用 → 确认无误后再写回配置。这样整个过程是可进退的。脚本里我会把「是否启用新版本」做成一个变量APPLY_NOW默认 0 表示只编译不生效人工确认后再设为 1 执行切换。3.2 脚本核心实现从环境检查到服务重启下面是一段精简版的升级脚本主体我在生产环境跑过多次逻辑上覆盖了主要故障点。#!/bin/bash # 麒麟离线升级 OpenSSH 9.8p1 脚本x86_64 / aarch64 通用 set -euo pipefail SRC_DIR/opt/ssh-update-bundle/openssh-9.8p1 DEPS_DIR/opt/ssh-update-bundle/deps PREFIX/usr/local/openssh SSHD_CONFIG_SRC/opt/ssh-update-bundle/sshd_config.rules APPLY_NOW${APPLY_NOW:-0} BACKUP_DIR/opt/ssh-backup # 1. 环境检查断言 root、依赖目录和备份目录存在 if [ $(id -u) -ne 0 ]; then echo [ERROR] 请使用 root 执行此脚本; exit 1 fi [ -d $SRC_DIR ] || { echo [ERROR] 未找到源码目录 $SRC_DIR; exit 1; } [ -d $BACKUP_DIR ] || { echo [ERROR] 未找到备份目录先执行备份; exit 1; } # 2. 依赖检查缺了就提示自动安装本地 RPM missing$(rpm -q --qf %{NAME}\n \ gcc make perl zlib-devel openssl-devel pam-devel 2/dev/null | \ grep -v is not installed | wc -l) # 注实际判断逻辑应为逐包检查此处为展示省略 if [ ${missing} -gt 0 ]; then echo [INFO] 安装离线依赖包... rpm -Uvh ${DEPS_DIR}/*.rpm --nodeps --force fi # 3. 编译安装到独立前缀目录不污染系统 cd $SRC_DIR make clean /dev/null 21 || true ./configure --prefix${PREFIX} \ --sysconfdir/etc/ssh \ --with-pam \ --with-ssl-dir/usr \ --with-zlib/usr \ --with-md5-passwords \ --with-privsep-path/var/empty/sshd make -j$(nproc) /tmp/ssh-build.log 21 make install /tmp/ssh-install.log 21 echo [INFO] 编译安装完成: ${PREFIX} # 4. 根据开关决定是否应用新版本 if [ ${APPLY_NOW} 1 ]; then install -m 0755 ${PREFIX}/sbin/sshd /usr/sbin/sshd install -m 0755 ${PREFIX}/bin/ssh /usr/bin/ssh install -m 0755 ${PREFIX}/bin/scp /usr/bin/scp cp -a ${PREFIX}/etc/ssh/* /etc/ssh/ 2/dev/null || true echo [INFO] 已复制新二进制和配置文件 systemctl restart sshd echo [INFO] sshd 已重启请保持当前连接另开终端验证 fi代码逻辑说明set -euo pipefail让脚本在任一命令失败时立即退出避免带着错误继续往下跑造成更严重的破坏。--prefix/usr/local/openssh把新版本隔离在独立目录好处是出问题时可以直接删掉整个目录回到原状。--sysconfdir/etc/ssh让配置文件仍使用系统原有路径这样/etc/ssh/sshd_config里的自定义配置能被继续读到。--with-pam开启 PAM 认证否则系统账号密码登录会失效。参数调整建议如果是 aarch64 环境--with-ssl-dir/usr通常不需要改如果是麒麟 V10 SP1 或更老的版本--with-md5-passwords可能需要去掉因为老版本 glibc 对 MD5 密码的处理在新 OpenSSH 里可能不兼容。make -j$(nproc)用满所有 CPU 核心加速编译内网机器如果资源紧张可以改成make -j2降低负载。3.3 配置保留与加密算法补充编译安装的新版 OpenSSH 会把默认 sshd_config 安装到/etc/ssh/但 install 过程不会删除原文件只是覆盖同名文件。原sshd_config被覆盖后你之前在文件里配置的PermitRootLogin、PasswordAuthentication、AllowUsers等全部失效这是很多人升级后登录行为变化的原因。脚本里我会把自定义配置项提前抽出来放到独立文件然后在 sshd_config 末尾用Include指令引入这样就算主配置被重置自定义规则还在。# 生成兼容性配置片段 cat /etc/ssh/sshd_config.d/10-custom.conf EOF PermitRootLogin no PasswordAuthentication yes PubkeyAuthentication yes # 兼容老客户端旧版 WinSCP / Xshell 使用 ssh-rsa 签名 HostKeyAlgorithms ssh-rsa PubkeyAcceptedAlgorithms ssh-rsa KexAlgorithms diffie-hellman-group14-sha1 Ciphers aes128-cbc,aes256-cbc EOF chmod 600 /etc/ssh/sshd_config.d/10-custom.conf这段配置解决的是「新版本安全策略过严导致老客户端连不上」的问题。OpenSSH 8.8 之后默认禁用了 ssh-rsa 签名如果你的内网里还有 Windows 7 自带的 SSH 客户端或者老版本 Xshell连接时会报no matching host key type found。追加这些算法是为了兼容既有终端等客户端全部升级后再移除即可。生产环境建议按需启用内网安全要求高的话可以只保留ssh-rsa和diffie-hellman-group14-sha1CBC 系列加密算法能不开就不开。4. 避坑记录五个让运维原地翻车的细节4.1 升级后 SSH 连不上SELinux 上下文没更新现象systemctl restart sshd返回成功但从其他机器 SSH 连接直接被拒journalctl -u sshd显示SELinux is preventing /usr/sbin/sshd from getattr access或者干脆没有任何日志连接超时。原因麒麟 V10 默认开启 SELinux/usr/sbin/sshd原有 RPM 包的 SELinux 上下文是ssh_exec_t而make install复制的新二进制上下文是usr_t或者继承临时目录的上下文。SELinux 在 enforcing 模式下直接阻止 sshd 执行关键操作。解决恢复正确上下文然后重启服务restorecon -Rv /usr/sbin/sshd /usr/bin/ssh /usr/bin/scp /etc/ssh systemctl restart sshd如果没有 restorecon 命令说明系统缺少 policycoreutils离线包提前准备好。另外注意/etc/ssh/sshd_config.d/新创建的配置文件也可能有上下文问题一并restorecon掉最省事。从那以后我把 restorecon 直接写进了脚本的 rest 阶段再没被这个问题坑过。4.2 密码正确却登录失败PAM 配置被 install 重置现象升级后从终端登录输入密码但认证失败日志显示pam_unix(sshd:auth): authentication failure但密码确认无误。原因新版 OpenSSH 编译时如果配置了--with-pammake install会把一份新的 PAM 服务文件写到$PREFIX/etc/pam.d/sshd。如果这个文件不存在或内容不完整sshd 在 PAM 阶段直接认证失败。更隐蔽的是部分发行版的/etc/pam.d/sshd使用了pam_faillock.so、pam_access.so这类扩展模块这些模块在新前缀目录下根本加载不到。解决检查并修正/etc/pam.d/sshd确保第一行是auth required pam_sepermit.so或auth substack password-auth具体取决于麒麟版本并确认没有引用不存在的模块。对比备份的旧文件是最快的方法diff /opt/ssh-backup/etc/pam.d-sshd.bak /etc/pam.d/sshd备份文件显示旧配置里如果没有pam_faillock.so而新配置有把它注释掉再重启 sshd。另外升级后UsePAM yes默认开启如果你的环境根本不需要 PAM比如纯密钥认证可以直接在 sshd_config 里设UsePAM no绕过这个问题。4.3 密钥登录突然失效目录权限和 authorized_keys 链路现象升级前密钥登录正常升级后公钥登录报Permission denied (publickey)但密码登录正常/var/log/secure里没有任何有效日志。原因新版本 OpenSSH 对~/.ssh目录和authorized_keys文件的权限检查变得更严格StrictModes yes默认开启只要目录属主不是用户本人或者组权限太大直接拒绝。常见的触发条件是你用 root 帮其他用户拷贝过 authorized_keys导致文件属主变成 root。解决检查和修正属主与权限chown -R user:user ~/.ssh chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys如果是 root 用户本身登录失败检查/root/.ssh/authorized_keys的 SELinux 上下文用restorecon -Rv /root/.ssh修复。另外如果升级前生成过老格式的 RSA 密钥1024 位新版 OpenSSH 9.8 会直接拒绝需要重新生成 3072 位以上密钥或启用PubkeyAcceptedAlgorithms ssh-rsa。4.4 编译报错 openssl 头文件缺失或版本不匹配现象./configure阶段报configure: error: *** Cant find recent OpenSSL libcrypto (see config.log for details)或者编译阶段报openssl/opensslv.h: No such file or directory。原因系统里只装了openssl运行库没装openssl-devel开发头文件。或者安装的openssl-devel版本比源码要求的低比如源码要求 OpenSSL 1.1.1 以上系统只有 1.1.1f 但头文件路径不对。解决离线安装 openssl-devel并确认头文件路径rpm -ivh /opt/ssh-update-bundle/deps/openssl-devel-*.rpm find /usr/include/openssl -name opensslv.h -exec grep OPENSSL_VERSION_TEXT {} \;如果版本确实太老最稳妥的路径是把新版 OpenSSL 也编译进独立前缀目录然后在 OpenSSH 的 configure 里指定--with-ssl-dir/usr/local/openssl。同时注意 LD_LIBRARY_PATH 要包含/usr/local/openssl/lib否则 sshd 启动时报libcrypto.so.1.1: cannot open shared object file。4.5 回退时 sshd 起不来动态库路径残留现象升级后想回退老版本把备份的 sshd 二进制复制回去结果systemctl start sshd失败报error while loading shared libraries: libcrypto.so.1.1: cannot open shared object file。原因老版本 sshd 二进制依赖的是系统的 libcrypto但你在升级新版本时可能通过LD_LIBRARY_PATH或ldconfig把新版本动态库路径写进了系统缓存导致老二进制去加载新库版本不匹配直接崩。解决回退时检查动态库路径是否被污染ldd /usr/sbin/sshd /sbin/ldconfig -p | grep libcrypto如果 libcrypto 指向了/usr/local/openssl/lib删除这个目录下的库缓存条目重新执行ldconfig。更稳妥的方式是在回退后重启一次机器确保动态加载器状态干净。我在脚本里加了回退模式的开关ROLLBACK1执行时会自动清理 ld.so.conf 里的新增路径避免手工排查。5. 验证与回退把升级当成一次可撤销的手术升级操作完成后不能只看systemctl status sshd显示 running 就算完事。我的验证顺序是先开一个新终端窗口用密钥和密码各登录一次确认都成功后再退出当前的老连接。如果新连接失败老连接还在你还有机会检查日志调整配置。如果新连接正常也不要急着把所有维护窗口关掉继续验证几个关键项。ssh -V ss -tlnp | grep :22 journalctl -u sshd --since 5 minutes ago | grep -iE error|fail|warning第一个命令确认新版本已生效第二个确认 sshd 确实在监听第三个看启动过程有没有隐藏的错误。日志里常见的Bad ssh-rsa signature之类说明客户端兼容性问题需要调整第 3.3 节的算法配置。另外验证一个隐藏项用ssh -T测试 sftp 子系统是否正常很多机器升级后Subsystem sftp路径不对导致文件传输失败。进阶做法是把编译好的 OpenSSH 打包成 RPM回退时直接 rpm 切换干净利落。用checkinstall或者手写 spec 文件都可以打成 RPM 后rpm -Uvh安装旧版本会保留为openssh-8.2p1出问题一条命令回退rpm -e openssh-9.8p1 rpm -ivh /opt/ssh-backup/rpms/openssh-8.2p1-*.rpm这套验证流程我每次都会强制走一遍尤其是「另开新连接登录」这一步绝不跳过——经历过一次在线升级把自己关在门外的尴尬后我养成了条件反射任何涉及 sshd 的操作先开第二个会话保命再谈其他。希望帮到你。本文还有配套的精品资源点击获取