为什么学这个
为了方便随时远程访问Windows服务器,我决定在 Windows 服务器上配置一下 OpenSSH Server。
本以为是一项“一条命令启动服务”的简单工作,结果却遭遇了服务无法启动、进程静默崩溃、公钥权限错乱等一系列极具 Windows 特色的连环坑。耗费了不少精力排查,特此将完整的避坑与配置流程总结成文,供大家参考。
核心内容 / 标准配置步骤(附踩坑记录)
如果是在Windows系统服务器上从头配置 Windows OpenSSH 并实现免密登录,正确且最少踩坑的路径应当如下:
-
彻底抛弃 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
- 问题表现:尝试使用
-
启动服务并设置自启:
PowerShell
Start-Service sshd Set-Service -Name sshd -StartupType 'Automatic'踩坑记录二:
Start-Service报错且调试模式(-d)无任何输出-
问题表现:执行启动命令提示失败后,我尝试直接运行
sshd.exe -d获取调试信息,甚至使用-V查看版本,结果程序直接闪退,连报错日志和 Exit Code 都没有留下。 -
原因剖析:
- 环境变量污染(核心元凶) :当时我处于 Conda 的
(base)虚拟环境中。Conda 会将自身的Library\bin强行注入系统PATH前列。OpenSSH 启动时错误加载了 Conda 环境中不兼容的底层加密库(如libcrypto.dll),导致瞬间内存崩溃。 - 系统自带版本过旧:Windows 可选功能默认安装的 OpenSSH 版本为极老的
7.7.2.3,该版本在较新系统中存在严重的兼容性 Bug。
- 环境变量污染(核心元凶) :当时我处于 Conda 的
-
解决方法:首先执行
conda deactivate退出虚拟环境。随后彻底卸载系统自带版本(Remove-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0),然后再执行步骤一的 MSI 手动安装。
-
-
修改服务端配置(绕过管理员组的巨坑) : 打开配置文件
C:\ProgramData\ssh\sshd_config,滚动到文件最底部。Windows 默认会把管理员账户的公钥强行重定向到一个系统公共目录,导致程序不去读你个人文件夹下的.ssh。 你需要找到以下两行代码,并在行首添加#号将它们注释掉:# Match Group administrators # AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys(注:如果不注释掉这两行,即使你后面把权限配出花来,系统也会直接无视你本人的
authorized_keys文件。) -
写入客户端公钥至
~/.ssh/authorized_keys,并严格重置文件权限。原理解析:为什么无密码的 Windows 必须用公钥?
由于我的服务器为了本地开机方便没有设置系统密码(空密码),如果直接通过 SSH 尝试登录,会被服务端无情拒绝。这是因为 Windows 的本地安全策略以及 OpenSSH 的默认配置(
PermitEmptyPasswords no)严禁任何空密码账户进行远程网络访问,以防局域网内的横向恶意渗透。因此,我们必须配置 SSH 密钥登录。这并不是“跳过”了密码,而是用密码学中的非对称加密验证(证明你持有私钥)替代了传统的明文密码核对。这样既满足了 Windows 严苛的网络安全校验规则,又实现了我们想要的“丝滑免密”体验。
-
客户端生成公钥: 在你的个人电脑(发起连接的机器,无论 Mac/Linux 还是另一台 Windows)终端执行以下命令。强烈推荐使用目前最安全、解析最快的
ed25519算法:ssh-keygen -t ed25519(执行后一路狂按回车键到底,不要输入任何 passphrase,这样才能实现真正的无感免密。)
-
服务端写入与权限锁死:
踩坑记录三:配置了公钥免密,但 SSH 依然要求输入密码
-
原因剖析:
- 记事本“自作聪明” :用记事本保存无后缀文件时,极易被暗中添加
.txt后缀(变为authorized_keys.txt)。 - 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
-
-