🧰 从源码编译并打包 OpenSSH(自定义安装路径)

适用于 Ubuntu / Debian 系统

📦 一、前置准备

# 安装必要依赖
apt update
apt install -y build-essential libssl-dev zlib1g-dev libpam0g-dev checkinstall

📁 二、下载并解压源码

cd /mnt
wget https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-10.3p1.tar.gz
tar -zxf openssh-10.3p1.tar.gz
cd openssh-10.3p1

⚙️ 三、编译配置参数

我们不覆盖系统原生 /usr/sbin/sshd
而是安装到 /usr/local/,以便独立运行。

./configure \
  --prefix=/usr/local \
  --sysconfdir=/etc/ssh \
  --with-md5-passwords \
  --with-pam

🏗️ 四、编译

make -j$(nproc)

📦 五、使用 checkinstall 打包 .deb 文件

checkinstall 会在安装的同时生成一个 .deb 包,便于安装、卸载、迁移。

checkinstall --install=no --pkgname=openssh-local

当提示输入信息时建议如下填写:

软件包将用下面的值来创建:
 
0 -  Maintainer: [ root@shiyaofei-virtual-machine ]
1 -  Summary: [ Package created with checkinstall 1.6.2 ]
2 -  Name:    [ openssh-local ]
3 -  Version: [ 10.3p1 ]
4 -  Release: [ 1 ]
5 -  License: [ GPL ]
6 -  Group:   [ checkinstall ]
7 -  Architecture: [ amd64 ]
8 -  Source location: [ openssh-10.3p1 ]
9 -  Alternate source location: [  ]
10 - Requires: [  ]
11 - Provides: [ openssh-local ]
12 - Conflicts: [  ]
13 - Replaces: [  ]
 

最终会生成:
openssh-local_10.3p1-1_amd64.deb


📜 六、添加自定义维护脚本(DEBIAN 目录)

解压deb包,修改DEBIAN/ 目录下的脚本文件。

dpkg-deb -R openssh-local_10.3p1-1_amd64.deb ssh-deb-pack/
cd ssh-deb-pack/
tmp
├── DEBIAN
│   ├── conffiles
│   └── control
└── usr
    ├── local
    └── share

1️⃣DEBIAN/preinst(安装前执行)

#!/bin/bash
set -e
 
# ============================================================
# 检查目标系统是否为 Ubuntu 18.04
# ============================================================
if [ -f /etc/os-release ]; then
    . /etc/os-release
    DISTRO_ID="${ID}"
    DISTRO_VERSION="${VERSION_ID}"
else
    echo "ERROR: 无法读取 /etc/os-release,无法确认系统版本" >&2
    exit 1
fi
 
if [ "${DISTRO_ID}" != "ubuntu" ] || [ "${DISTRO_VERSION}" != "18.04" ]; then
    echo "============================================================" >&2
    echo "ERROR: 此软件包仅支持 Ubuntu 18.04 (Bionic Beaver)" >&2
    echo "       当前系统为: ${PRETTY_NAME}" >&2
    echo "============================================================" >&2
    exit 1
fi
 
# ============================================================
# 停止原有 SSH 服务
# ============================================================
echo "==> 系统版本检查通过:${PRETTY_NAME}"
echo "==> 停止原有 SSH 服务"
systemctl stop ssh || true
 
exit 0

2️⃣ DEBIAN/postinst(安装后执行)

#!/bin/bash
set -e
# postinst:在文件安装完成后执行。用于修改 systemd 配置并启动服务。
 
SERVICE_FILE="/lib/systemd/system/ssh.service"
SSHD_CONF="/etc/ssh/sshd_config"
 
# 修改 systemd 服务文件路径,指向 /usr/local/sbin/sshd
if [ -f "$SERVICE_FILE" ]; then
    echo "==> 修改 systemd 服务文件以使用 /usr/local/sbin/sshd"
    sed -i 's|/usr/sbin/sshd|/usr/local/sbin/sshd|g' "$SERVICE_FILE"
fi
 
# 创建安全隔离目录 /var/empty
mkdir -p /var/empty
chown root:root /var/empty
chmod 755 /var/empty
 
# ============================================================
# 修改 sshd_config
# ============================================================
 
# 备份
cp /etc/pam.d/sshd /etc/pam.d/sshd.before
cp "$SSHD_CONF" "${SSHD_CONF}.before"
 
# 清理旧算法配置
sed -i '/^[[:space:]]*KexAlgorithms/d' "$SSHD_CONF"
sed -i '/^[[:space:]]*GSSAPIKexAlgorithms/d' "$SSHD_CONF"
sed -i '/^[[:space:]]*HostKeyAlgorithms/d' "$SSHD_CONF"
 
# PermitRootLogin yes(幂等)
if ! grep -Eq '^[[:space:]]*PermitRootLogin[[:space:]]+yes\b' "$SSHD_CONF"; then
    echo "PermitRootLogin yes" >> "$SSHD_CONF"
fi
 
# UsePAM yes(存在则替换,不存在则追加)
if grep -Eq '^[[:space:]]*#?[[:space:]]*UsePAM' "$SSHD_CONF"; then
    sed -i 's/^[[:space:]]*#\?[[:space:]]*UsePAM.*/UsePAM yes/' "$SSHD_CONF"
else
    echo "UsePAM yes" >> "$SSHD_CONF"
fi
 
# 恢复 pam
/bin/cp /etc/pam.d/sshd.before /etc/pam.d/sshd
 
# HostKeyAlgorithms +ssh-rsa(幂等)
if ! grep -Eq '^[[:space:]]*HostKeyAlgorithms[[:space:]]+\+ssh-rsa\b' "$SSHD_CONF"; then
    echo "HostKeyAlgorithms +ssh-rsa" >> "$SSHD_CONF"
fi
 
# ============================================================
 
# 重新加载 systemd 并启动新 ssh 服务
systemctl daemon-reload || true
systemctl enable ssh || true
systemctl restart ssh || true
 
echo "==> OpenSSH 10.3p1 (local) 已启动"
exit 0

3️⃣ DEBIAN/prerm(卸载前执行)

#!/bin/bash
set -e
# prerm:卸载前执行,停止当前 ssh 服务
 
echo "==> 停止 openssh-local 服务"
systemctl stop ssh || true
exit 0

4️⃣ DEBIAN/postrm(卸载后执行)

#!/bin/bash
set -e
# postrm:卸载后执行,恢复系统默认 sshd 路径并重启系统 ssh 服务
 
SERVICE_FILE="/lib/systemd/system/ssh.service"
 
if [ -f "$SERVICE_FILE" ]; then
    echo "==> 恢复 systemd 服务文件使用 /usr/sbin/sshd"
    sed -i 's|/usr/local/sbin/sshd|/usr/sbin/sshd|g' "$SERVICE_FILE"
fi
 
systemctl daemon-reload || true
systemctl restart ssh || true
echo "==> 已恢复系统默认 OpenSSH 服务"
exit 0

🔐 七、设置脚本权限

chmod 755 DEBIAN/{preinst,postinst,prerm,postrm}

📦 八、重新打包deb文件

dpkg-deb -b ssh-deb-pack/ openssh-local_10.3p1-1_amd64.deb

🚀 九、安装自定义 OpenSSH 包

dpkg -i openssh-local_10.3p1-1_amd64.deb

安装输出示例:

# dpkg -i openssh-local_10.3p1-1_amd64.deb 
Selecting previously unselected package openssh-local.
(Reading database ... 132556 files and directories currently installed.)
Preparing to unpack openssh-local_10.3p1-1_amd64.deb ...
==> 系统版本检查通过:Ubuntu 18.04.6 LTS
==> 停止原有 SSH 服务
Unpacking openssh-local (10.3p1-1) ...
Setting up openssh-local (10.3p1-1) ...
==> 修改 systemd 服务文件以使用 /usr/local/sbin/sshd
Synchronizing state of ssh.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install enable ssh
==> OpenSSH 10.3p1 (local) 已启动
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
(base) root@jianrong231:/mnt# 
 

🧹 十、卸载并恢复系统原生 OpenSSH

dpkg -r openssh-local

输出示例:

root@shiyaofei-virtual-machine:~# dpkg --remove openssh-local 
(正在读取数据库 ... 系统当前共安装有 233418 个文件和目录。)
正在卸载 openssh-local (10.3p1-1) ...
==> 停止 openssh-local 服务
==> 恢复 systemd 服务文件使用 /usr/sbin/sshd
==> 已恢复系统默认 OpenSSH 服务
正在处理用于 man-db (2.10.3-1) 的触发器 ...

🔍 十一、附加说明

内容说明
/usr/local/sbin/sshd你的新编译版 OpenSSH 运行路径
/usr/sbin/sshd系统默认版本
/var/emptySSH 特权分离安全目录,必须存在且属主为root:root,权限为755
DEBIAN/control定义包名、版本、依赖关系等信息
checkinstall自动生成 .deb包并更新 dpkg 数据库

十二、验证

which sshd
# 输出应为 /usr/local/sbin/sshd
 
sshd -V
# OpenSSH_10.3p1, OpenSSL ...

✅ 📖十三、目录结构参考

.
├── DEBIAN
│   ├── conffiles
│   ├── control
│   ├── postinst
│   ├── postrm
│   ├── preinst
│   └── prerm
└── usr
    ├── local
    └── share