
简介面向Ubuntu服务器运维及安全管理人员这份资源提供将OpenSSH升级至9.5p1并同步更新zlib压缩库的一体化方案。当前老版本OpenSSH常存在已知安全漏洞升级可加固远程登录通道而zlib新版本有助于提升压缩性能与兼容性。资源共3个文件包括openssh与zlib的源码压缩包gz格式和自动化升级脚本sh格式整个zip包仅3.18MB轻量易用。已有705人学习/下载适合需要快速修复漏洞、减少手动编译出错概率的运维场景。相比逐条执行命令脚本可依次完成依赖检查、源码解压、zlib及OpenSSH编译安装、sshd服务重启和版本验证等环节并提示备份旧版本配置以便回滚帮助读者在节省时间的同时降低升级风险。对于需要批量维护多台Ubuntu主机的管理员这套资源还能作为标准化升级模板结合脚本审阅、日志监控与官方安全公告跟踪形成可持续的安全运维流程。1. Ubuntu 一键升级 openssh 9.5p1一次把 sshd 和 zlib 1.3 一起换掉在一台远程 Ubuntu 服务器上执行 openssh 升级最刺激的时刻不是下载源码而是脚本跑到一半你当前这个 ssh 会话突然断了——因为你正在升级的进程恰好就是你正在使用的进程。很多生产机的 openssh 还停在 8.x安全基线要求升到固定版本 9.5p1而 9.5p1 的依赖链里又明确要求 zlib 高于 1.2.x所以标题里才会把 openssh 9.5p1 和 zlib 1.3 绑在一起说。这篇我用一套可复现的一键脚本讲清楚编译参数、备份策略、systemd 联动和回滚兜底适合 Linux 运维、基线检查执行者和自己折腾 Ubuntu 服务器的开发。真正老练的运维都知道所谓一键不是让你闭眼跑而是把每一步的后悔药提前埋好。2. 升级前的盘查openssh 9.5p1 对 zlib 1.3 的依赖到底卡在哪2.1 为什么是 9.5p1 而不是随缘升最新Ubuntu 的 apt 源里 openssh 版本是跟着发行版走的20.04 自带的版本大约是 8.2p122.04 自带 8.9p1想在原系统上通过 apt upgrade 把版本跳到 9.5p1 基本不可能除非换第三方源或者等官方 backports。而 openssh 9.5p1 这一版比较特殊它在发布说明里集中修复了 ssh-agent 相关的安全问题同时把推荐依赖从 zlib 1.2.x 抬到了 1.3正好对应标题里那个 zlib-1.3。所以很多内部安全基线和等保加固项都把“openssh 9.5p1、zlib 1.3”钉成了固定验收条件。如果你没有硬性版本要求直接升到当时最新 portable 版当然更省心但 9.5p1 反而是那批机器上最不容易引入新变数的选择它对 OpenSSL 1.1.1 的兼容性稳定20.04 自带 OpenSSL 1.1.1f 也能正常编过。9.6 之后的版本开始引入对 Terrapin 攻击的缓解键盘逻辑对 OpenSSL 版本和底层 crypto 库的检测更挑剔反而容易出现 configure 阶段就需要折腾的情况。我一般把 9.5p1 当作“求稳求过检”的中间版本脚本参数和依赖处理也和更新版本通用。2.2 zlib 1.3 在升级里的位置一个堆溢出 CVE 引发的连带动作zlib 1.3 本身不是为 openssh 而发的但它修掉了 1.2.x 时代一个在 inflate 流程里的堆溢出问题对应的公开编号是 CVE-2023-45853。openssh 作为重度依赖 zlib 的组件sshd 在密钥交换、压缩传输、authorized_keys 解析路径里都会触及 zlib 的 API。Ubuntu 20.04/22.04 自带的 zlib 还停在 1.2.11如果只升级 openssh 而不处理 zlib新版本能够在老 zlib 上编过但安全扫描器一查动态链接库版本立马又会把 zlib 1.2.11 的 CVE 重新列出来。这里最容易翻车的不是 openssh 本身而是 zlib 的安装位置。多数人习惯./configure --prefix/usr make install这么干会把它直接覆盖进系统库路径后续凡是依赖 libz.so.1 的程序全都换到了新 ABI。zlib 官方说 1.3 向后兼容但生产环境里我见过有老程序在升级后出现行为差异排查成本很高。稳妥做法是把 zlib 1.3 装进独立的/usr/local/zlib-1.3再让 openssh 编译时通过--with-zlib指过去系统其余程序继续用原有 libz互不干扰。这样既满足 sshd 的依赖要求又不扩大爆炸半径。2.3 编译前的系统检查gcc、OpenSSL 头文件和 Ubuntu 版本三件事在一键脚本跑起来之前先把底数摸清。要确认当前 openssh 版本、zlib 版本、OpenSSL 的链接库和 gcc 工具链是否齐全。Ubuntu 上最常见的失败不是脚本逻辑错误而是这台机器压根没装 build-essential网上搜出来的一堆“ubuntu 安装 gcc 失败”帖子九成都是源没更新或源 404。直接看下面的命令ssh -V 21 grep -i zlib_version /usr/include/zlib.h | head -1 ls -l /usr/lib/ssl dpkg -l | grep -E build-essential|libssl-dev|gcc|make | awk {print $2, $3}ssh -V的版本信息会打到 stderr所以必须带21否则你在脚本里拿不到输出。grep ZLIB_VERSION是读编译期头文件版本注意运行时实际用的可能是/lib/x86_64-linux-gnu/libz.so.1两者不一致也算正常我们后面用ldd看的是 sshd 实际链接的库。/usr/lib/ssl是 Ubuntu 上 openssl 的统一软链目录检查它的存在性是为了确认后续 configure 时--with-ssl-dir有地方可指。然后是版本判断。24.04 自带的 openssh 已经高于 9.5p1可以直接跳过本方案20.04 和 22.04 才是主力目标。下面是常见自带的版本对照Ubuntu 版本自带 openssh 的大致版本自带 zlib是否建议本方案20.048.2p11.2.11建议22.048.9p11.2.11建议24.04高于 9.5p1高于 1.2.x无需依赖包必须在源码编译前装齐build-essential、gcc、make、libssl-dev、libpam0g-dev、pkg-config、zlib1g-dev。libssl-dev 缺了会直接让 openssh 的 configure 报找不到 libcryptolibpam0g-dev 缺了会让编译出的 sshd 不包含 PAM 支持登录后你会发现密码认证和系统账号认证行为全部变得很怪。检查完这三件事就可以进正题写脚本了。3. 一键升级脚本落地从备份到编译安装的全过程3.1 脚本设计先备份再动手重启留给人来确认所谓一键升级我理解的正确形态是你把脚本交给机器跑它自动完成环境检查、依赖安装、源码下载、编译安装、配置校验这几件机械化的事但把最后一步“重启 sshd”留给人亲自动手。原因是 sshd 一旦重启当前会话可能立刻断掉如果脚本里写了自动重启而你又没有第二通道等于亲手把自己关在门外。所以整个脚本的执行顺序我固定为六段检查环境 - 备份配置与旧二进制 - 编译安装 zlib 1.3 - 编译安装 openssh 9.5p1 - 收尾权限与语法检查 - 打印结果。备份必须放在编译之前因为后续任何一步失败你都能靠备份快速回到升级前的状态。备份目录带时间戳不要用固定文件名防止二次升级时把第一次的备份冲掉。另一个设计点源码包下载做了本地缓存检测。如果/root/ssh_upgrade下已经有zlib-1.3.tar.gz和openssh-9.5p1.tar.gz直接跳过 wget。官方源在国外速度时好时坏把下载动作和编译动作解耦你就可以提前把包传到服务器上或者从镜像站下载后改名放进目录再执行一键脚本。3.2 完整脚本zlib 1.3 编译、openssh 9.5p1 编译与安装#!/bin/bash # Ubuntu 一键升级 openssh 9.5p1 zlib 1.3 # 用法root 用户执行建议放在 tmux/screen 会话里 set -e ZLIB_VER1.3 SSH_VER9.5p1 WORK_DIR/root/ssh_upgrade BACKUP_DIR${WORK_DIR}/backup_$(date %Y%m%d_%H%M%S) ZLIB_SRChttps://www.zlib.net/fossils/zlib-${ZLIB_VER}.tar.gz SSH_SRChttps://cdn.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-${SSH_VER}.tar.gz echo [1/6] 检查当前版本与编译环境 if [ $(id -u) ! 0 ]; then echo 请用 root 运行; exit 1; fi ssh -V 21 grep ZLIB_VERSION /usr/include/zlib.h | head -1 || true apt-get update apt-get install -y build-essential gcc make libssl-dev libpam0g-dev pkg-config zlib1g-dev echo [2/6] 备份现有 ssh 配置与二进制 mkdir -p ${BACKUP_DIR} cp -a /etc/ssh ${BACKUP_DIR}/etc_ssh cp /usr/sbin/sshd ${BACKUP_DIR}/sshd.bin.old 2/dev/null || true cp /usr/bin/ssh ${BACKUP_DIR}/ssh.bin.old 2/dev/null || true echo [3/6] 编译安装 zlib ${ZLIB_VER} mkdir -p ${WORK_DIR} cd ${WORK_DIR} [ -f zlib-${ZLIB_VER}.tar.gz ] || wget ${ZLIB_SRC} tar -xzf zlib-${ZLIB_VER}.tar.gz cd zlib-${ZLIB_VER} ./configure --prefix/usr/local/zlib-${ZLIB_VER} make -j$(nproc) make install echo /usr/local/zlib-${ZLIB_VER}/lib /etc/ld.so.conf.d/zlib-${ZLIB_VER}.conf ldconfig echo [4/6] 编译安装 openssh ${SSH_VER} cd ${WORK_DIR} [ -f openssh-${SSH_VER}.tar.gz ] || wget ${SSH_SRC} tar -xzf openssh-${SSH_VER}.tar.gz cd openssh-${SSH_VER} ./configure \ --prefix/usr \ --sysconfdir/etc/ssh \ --with-zlib/usr/local/zlib-${ZLIB_VER} \ --with-ssl-dir/usr/lib/ssl \ --with-pam \ --disable-strip make -j$(nproc) /usr/sbin/sshd -t || { echo 旧 sshd 配置检查未通过中止; exit 1; } make install echo [5/6] 收尾补齐目录并二次语法检查 mkdir -p /run/sshd chmod 0755 /run/sshd /usr/sbin/sshd -t echo [6/6] 升级完成版本信息如下 ssh -V 21 ldd /usr/sbin/sshd | grep zlib echo 备份目录${BACKUP_DIR} echo 最后请手动执行systemctl restart ssh这套脚本的核心逻辑是先编译 zlib 到一个独立目录再用--with-zlib让 openssh 的 configure 找到它。--prefix/usr和--sysconfdir/etc/ssh是两个关键设置--prefix/usr保证 sshd 安装到/usr/sbin/sshd跟 Ubuntu 系统服务里 ExecStart 的路径一致否则装上后 systemd 会找不到二进制--sysconfdir/etc/ssh让新 sshd 读取原有配置不会去/usr/local/etc找一套新的空配置。--with-ssl-dir/usr/lib/ssl是在 Ubuntu 上链接系统 OpenSSL 的常规写法。--with-pam必须加Ubuntu 的认证链路依赖 PAM不加这个参数编译出的 sshd 在密码登录时会绕过一系列 pam 模块。脚本里还埋伏了一个保护在make install覆盖旧 sshd 之前先用/usr/sbin/sshd -t检查一遍现有配置语法。如果之前有人把 sshd_config 改坏了脚本会在这一步停下来而不是把坏配置和好二进制混在一起给你制造更大问题。make install完成后会再次执行语法检查此时检查的就是新版 sshd 对现有配置文件的兼容性。3.3 configure 参数逐个拆路径与依赖库的绑定关系可能有人会问为什么 zlib 不直接用系统已有的非要自己编一份因为 20.04/22.04 系统源里的 zlib 没有 1.3 版本apt 装不上。自己编一份装到独立目录再把 openssh 编译时的--with-zlib指过去是最可控的做法。下面这几个参数在实际调整时最值得关注configure 参数含义调整场景--prefix/usr二进制安装到 /usr 体系想装到 /usr/local 时要同步改 systemd 的 ExecStart不推荐--sysconfdir/etc/ssh配置文件目录不设置会去 /usr/local/etc导致 sshd_config 丢失--with-zlib/usr/local/zlib-1.3指定 zlib 头文件与库路径换 zlib 版本时同步修改--with-ssl-dir/usr/lib/sslOpenSSL 根目录手动编译 OpenSSL 的机器改成对应目录--with-pam启用 PAM 认证不启用会破坏 Ubuntu 密码登录体系我见过有些人习惯加--without-openssl或者--with-openssl这两个参数如果理解不透很容易把 sshd 编成不支持 RSA 密钥交换的版本。没有特殊需求就别碰它们保持默认让 openssh 自动检测系统 OpenSSL 即可。--disable-strip保留了二进制符号之后出问题可以 gdb 调试不占多少空间。3.4 系统服务联动ssh.service 与 ldconfig 为什么才是升级完的关键openssh 编译安装完成后真正决定能不能起来的是两件和源码无关的事systemd 服务文件指向的二进制路径以及动态链接库能否被加载。Ubuntu 的 ssh.service 在/lib/systemd/system/ssh.service默认 ExecStart 是/usr/sbin/sshd -D。因为 configure 里加了--prefix/usrmake install 后新 sshd 恰好覆盖了旧文件服务单元文件不需要改。这也是我坚持用--prefix/usr而不是/usr/local的最现实理由。但新 sshd 链接的 libz 在/usr/local/zlib-1.3/lib这个路径不在系统默认搜索范围里所以脚本里写了/etc/ld.so.conf.d/zlib-1.3.conf并执行ldconfig。这一步漏掉的话systemctl restart ssh会直接报error while loading shared libraries: libz.so.1: cannot open shared object file而ssh -V却一切正常因为 ssh 命令本身可能链接的仍是系统库。检查确认时用ldd /usr/sbin/sshd看是否指向新路径ldd /usr/sbin/sshd | grep -E zlib|ssl|crypto正常看到三行都指向具体路径就行重点确认 libz 一行末尾带的是/usr/local/zlib-1.3/lib而不是/lib/x86_64-linux-gnu。另一个容易忽略的目录是/run/sshd新版 sshd 在启动时会向这里写特权分离相关的文件Ubuntu 清空/run后目录可能不存在表现为连接后卡住或直接报错。脚本的第 5 步已经把这个坑填上了。注意如果我上面那句ldd的输出里 libz 仍指向系统老路径不要慌。优先检查刚才写的 ld.so.conf.d 文件是否生效而不是把 zlib 重新装一遍。4. 升级避坑连接中断、PAM 失效和 lib 找不到的现场处置4.1 升级跑到一半 ssh 断连网上说的“ubuntu ssh无法连接”大多数是这个原因现象脚本在编译阶段一切正常到make install或systemctl restart ssh时当前终端瞬间卡死然后提示连接关闭重新 ssh 也连不上了。原因你正在替换和重启的进程恰恰是自己这条连接的服务端。旧 sshd 进程被停掉的一瞬间所有基于它的会话全部断开。如果脚本里有自动重启这个断连时间点是不可控的。解决从源头上把“编译安装”和“重启服务”拆成两步。上面脚本里我已经把systemctl restart ssh留在最后人工执行。执行时如果服务器有 IPMI、VNC 或同网段另一台跳板机可以先开着备用通道再切换。没有条件的用 tmux 挂脚本而不是裸跑终端这样就算断连服务起来后重新登进去还能看到脚本的完整输出。4.2 sshd 起不来报 libz.so 或 libcrypto.so 找不到现象ssh -V能正常打出版本但systemctl restart ssh失败journalctl -u ssh里看到error while loading shared libraries。原因ssh -V调用的是/usr/bin/ssh客户端它链接的库和新装的 sshd 不一样。新 sshd 在/usr/sbin/sshd依赖 zlib 1.3 的独立库路径而这个路径没有被 ldconfig 提前登记。解决先ldd /usr/sbin/sshd | grep not found看到确切缺谁的库再检查/etc/ld.so.conf.d/下有没有对应 conf 文件。libz 的问题是忘了写 zlib 路径libcrypto 的问题是--with-ssl-dir/usr/lib/ssl指向的开源 libssl 版本和运行时不一致在 Ubuntu 20.04 上通常要确认 libssl-dev 版本是 1.1.1 系列别让系统里混入其他 OpenSSL 目录。治完记得再跑一次ldconfig /usr/sbin/sshd -t。4.3 升级后密码和公钥全部 Permission denied现象版本已经是 9.5p1但任何用户都登录不进去日志里反复出现Failed password或Authentication refused。原因编译时丢了--with-pamsshd 走了默认的影子密码验证逻辑没有完整执行 Ubuntu 的 PAM 栈包括账户锁定、登录限制、faillock 等模块全部缺席。另一种常见情况是 make install 后/etc/ssh目录权限或主机密钥权限发生变化sshd 拒绝读取 HostKey。解决先用备份的/etc/ssh目录对比差异重点看 sshd_config 和主机密钥权限。主机密钥文件必须是 600目录必须是 755。如果 configure 参数里没有 PAM 就重新编译只是权限问题就按下面恢复chmod 600 /etc/ssh/ssh_host_*_key chmod 644 /etc/ssh/ssh_host_*_key.pub chmod 700 /root/.ssh chmod 600 /root/.ssh/authorized_keys恢复完再/usr/sbin/sshd -t确认没有报错最后重启服务。验证登录时不要只测一种方式密码和公钥都过一遍因为这两个走的是完全不同的认证路径。4.4 把 zlib 装进 /usr 之后的系统级连锁翻车现象升级完成后系统其余依赖 zlib 的程序跑起来行为异常有的直接段错误有的在文件压缩解压时报莫名错误。原因图省事把 zlib 1.3 用--prefix/usr直接覆盖进了系统库目录。虽然 zlib 官方声明 1.3 保持 ABI 兼容但生产环境里总有程序是用老头文件静态编译或者依赖特定行为升级后正是这些边角程序先暴露问题。CentOS、Alibaba Cloud Linux 那边升级 openssh 要处理 rpm 依赖Ubuntu 这边不拆 rpm代价就是编译产物游离于 dpkg 管理系统之外你不能指望dpkg -V帮你发现库被换过。解决这篇脚本里已经把 zlib 装到/usr/local/zlib-1.3从根上避开了这个问题。如果你已经翻车覆盖了系统库最干净的办法是重新安装 Ubuntu 原生的 zlib1g 包把系统库恢复出厂然后按独立 prefix 路径再编一次 openssh。别尝试手工把老 libz 复制回去这样会再次搞乱链接关系。4.5 configure 报 Cant find OpenSSL headers 或 zlib.h 找不到现象执行 ./configure 后出现*** Cant find recent OpenSSL libcrypto或fatal error: zlib.h: No such file or directory编译直接中断。原因缺的是编译期头文件不是运行库。libssl-dev没装时系统里可能只有 libssl.so.1.1 而没有头文件目录zlib1g-dev没装时缺少/usr/include/zlib.h。网上常见的“ubuntu 安装 gcc 失败”基本也是同类问题apt 源没上来就装包结果一堆依赖报 404。解决别跟 configure 置气按第 2.3 节的依赖清单一次性装齐。装完务必执行apt-get update先刷新索引否则装的是什么旧版残包都说不清。如果安装过程提示依赖关系破坏先apt --fix-broken install再重试。治完这个zlib 头文件检查通过configure 大概率顺利往前推进。5. 升级后的验证清单ssh -V 之外还要测的四件事版本号只是第一关。我见过有人升级完看到ssh -V输出 9.5p1 就宣布收工结果 scp 大文件时压缩通道异常、公钥登录时后台报错全都没被发现。如果你照这篇脚本做的按下面这个顺序验证每项一两分钟能省掉后续半夜被叫起来的麻烦。先跑静态检查/usr/sbin/sshd -t确认配置语法无错ssh -V 21确认版本号ldd /usr/sbin/sshd | grep zlib确认链接到了 /usr/local/zlib-1.3。静态检查通过后执行systemctl restart ssh注意这次重启你要做好断连预案。服务回来后再开一个会话测四件动态的事验证项命令预期结果服务状态systemctl status ssh --no-pageractive (running)无 failed密码登录新开会话正常输入密码一次进入无延迟公钥登录关闭密码认证后测试公钥免密进入文件传输scp /etc/hostname userhost:/tmp/传输成功大文件不中断scp 这一步很值得加。openssh 9.5p1 对加密算法和压缩通道的默认策略有调整如果系统里还有老客户端在连这台机器可能出现“能登录但传大文件失败”的诡异局面。传一个 100MB 左右的文件观察是否报connection closed。出了问题先看/var/log/auth.log里 sshd 的报错段不要凭感觉去改 sshd_config 的 Ciphers 和 MACs除非日志明确指向算法协商失败。最后把备份目录留着。我个人的习惯是备份保留至少一周等确认没有后续问题再清理。万一新版本在老王牌服务器上触发什么玄学问题备份里的旧 sshd、旧配置就是你最快的后悔药。到那时候恢复也就三条命令停服务、把备份目录拷回去、重启。我现在不管升级哪台机器都会先起一个 tmux把备份目录打上日期再跑脚本最后手动重启而不是一股脑 package 到位。这套流程跑多了你会发现真正的风险从来不在编译而在你对过程失去控制的那一刻。希望帮到你。本文还有配套的精品资源点击获取