【踩坑实录】Windows 11/10 部署 OpenSSH 服务“静默崩溃”与服务器无密码下的免密登录修复指南

9 阅读4分钟

为什么学这个

为了方便随时远程访问Windows服务器,我决定在 Windows 服务器上配置一下 OpenSSH Server。

本以为是一项“一条命令启动服务”的简单工作,结果却遭遇了服务无法启动、进程静默崩溃、公钥权限错乱等一系列极具 Windows 特色的连环坑。耗费了不少精力排查,特此将完整的避坑与配置流程总结成文,供大家参考。


核心内容 / 标准配置步骤(附踩坑记录)

如果是在Windows系统服务器上从头配置 Windows OpenSSH 并实现免密登录,正确且最少踩坑的路径应当如下:

  1. 彻底抛弃 Windows 默认可选功能中的旧版 OpenSSH,直接前往 GitHub 下载官方最新版(v8.9+)的 MSI 安装包进行部署。

    踩坑记录一:国内网络下命令行下载 MSI 失败

    • 问题表现:尝试使用 Invoke-WebRequest 从 GitHub 下载新版 MSI 时,遭遇 WebException 网络超时。且官方 Release 标签由于拼写规范问题(如 -Release 误写或实际为 -Beta),极易导致 404。
    • 解决方法:放弃命令行下载,直接在浏览器中使用国内镜像加速节点手动下载并安装。
    • 有效下载链接https://github.com/PowerShell/Win32-OpenSSH/releases/download/10.0.0.0p2-Preview/OpenSSH-Win64-v10.0.0.0.msi
  2. 启动服务并设置自启

    PowerShell

    Start-Service sshd
    Set-Service -Name sshd -StartupType 'Automatic'
    

    踩坑记录二:Start-Service 报错且调试模式(-d)无任何输出

    • 问题表现:执行启动命令提示失败后,我尝试直接运行 sshd.exe -d 获取调试信息,甚至使用 -V 查看版本,结果程序直接闪退,连报错日志和 Exit Code 都没有留下。

    • 原因剖析

      1. 环境变量污染(核心元凶) :当时我处于 Conda 的 (base) 虚拟环境中。Conda 会将自身的 Library\bin 强行注入系统 PATH 前列。OpenSSH 启动时错误加载了 Conda 环境中不兼容的底层加密库(如 libcrypto.dll),导致瞬间内存崩溃。
      2. 系统自带版本过旧:Windows 可选功能默认安装的 OpenSSH 版本为极老的 7.7.2.3,该版本在较新系统中存在严重的兼容性 Bug。
    • 解决方法:首先执行 conda deactivate 退出虚拟环境。随后彻底卸载系统自带版本(Remove-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0),然后再执行步骤一的 MSI 手动安装。

  3. 修改服务端配置(绕过管理员组的巨坑) : 打开配置文件 C:\ProgramData\ssh\sshd_config,滚动到文件最底部。Windows 默认会把管理员账户的公钥强行重定向到一个系统公共目录,导致程序不去读你个人文件夹下的 .ssh你需要找到以下两行代码,并在行首添加 # 号将它们注释掉:

    # Match Group administrators
    #       AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys
    

    (注:如果不注释掉这两行,即使你后面把权限配出花来,系统也会直接无视你本人的 authorized_keys 文件。)

  4. 写入客户端公钥~/.ssh/authorized_keys,并严格重置文件权限

    原理解析:为什么无密码的 Windows 必须用公钥?

    由于我的服务器为了本地开机方便没有设置系统密码(空密码),如果直接通过 SSH 尝试登录,会被服务端无情拒绝。这是因为 Windows 的本地安全策略以及 OpenSSH 的默认配置(PermitEmptyPasswords no严禁任何空密码账户进行远程网络访问,以防局域网内的横向恶意渗透。

    因此,我们必须配置 SSH 密钥登录。这并不是“跳过”了密码,而是用密码学中的非对称加密验证(证明你持有私钥)替代了传统的明文密码核对。这样既满足了 Windows 严苛的网络安全校验规则,又实现了我们想要的“丝滑免密”体验。

    1. 客户端生成公钥: 在你的个人电脑(发起连接的机器,无论 Mac/Linux 还是另一台 Windows)终端执行以下命令。强烈推荐使用目前最安全、解析最快的 ed25519 算法:

      ssh-keygen -t ed25519
      

      (执行后一路狂按回车键到底,不要输入任何 passphrase,这样才能实现真正的无感免密。)

    2. 服务端写入与权限锁死:

      踩坑记录三:配置了公钥免密,但 SSH 依然要求输入密码

      • 原因剖析

        1. 记事本“自作聪明” :用记事本保存无后缀文件时,极易被暗中添加 .txt 后缀(变为 authorized_keys.txt)。
        2. OpenSSH 的权限洁癖:如果公钥文件继承了其他系统用户或组的读取权限,SSH 进程会判定其“不安全”并直接丢弃,强制回退到密码验证。
      • 解决方法(纯命令行一键修复) :为了绕过记事本后缀问题和手动改权限的繁琐,直接在服务端管理员 PowerShell 执行以下脚本(注意替换真实用户名和你的公钥):

        PowerShell

        # 1. 命令行写入公钥(绝对不带 .txt 后缀)
        $pubKey = "ssh-ed25519 AAAAC3... 你的公钥内容"
        Set-Content -Path "C:\Users\你的用户名.ssh\authorized_keys" -Value $pubKey -Force
        
        # 2. 剥离继承权限并锁死所有权
        $keyPath = "C:\Users\你的用户名.ssh\authorized_keys"
        icacls $keyPath /inheritance:r
        icacls $keyPath /grant "SYSTEM:F"
        icacls $keyPath /grant "BUILTIN\Administrators:F"
        icacls $keyPath /grant "$env:USERNAME:F"
        
        # 3. 重启服务
        Restart-Service sshd