搞 Windows 运维的人,迟早都会碰到要给 Windows 机器开 SSH 的需求。我在好几个项目里都遇到过这种情况:要么是机房里的 Windows Server 需要统一纳管,要么是开发机要从 Linux 跳板机过去传文件,再要么是 Git 要连 Windows 上的仓库。以前大家习惯用某些远程桌面或者 FTP 凑合,但真正进了生产环境,什么协议都不如 SSH 干净、安全、可控。
这个需求的答案其实很明确:Windows 自带的 OpenSSH。但真正折腾起来,在线装和离线装完全是两套路子。在线装很简单,点几下鼠标或者敲一条命令就行;离线装要面对一堆依赖和权限问题,稍不注意就会卡在进度条上。这篇文章我把两条路都走一遍,把命令、参数、报错、排查方法都整理清楚,给需要的人当个参考。
1. 动手前先想清楚:Windows上的OpenSSH到底能解决什么问题
1.1 为什么要在Windows上部署OpenSSH
很多人对 Windows 上开 SSH 的第一反应是“没必要”。但实际上,只要你的环境里同时存在 Linux 和 Windows 机器,SSH 几乎是打通这两种系统最省事的桥。
先说远程管理。Windows 自带的远程桌面(RDP)确实好用,但它是图形界面协议,带宽占用大,而且很多内网环境会限制 3389 端口。OpenSSH 基于命令行,走 22 端口,只要网络策略允许 TCP 流量,你就能用ssh user@host直接进去执行命令,查看服务状态、重启服务、拉日志,全部可以用脚本完成。我在一个混合机房项目里,几十台 Windows 服务器全靠 SSH 统一跑巡检命令,比挨个开远程桌面效率高出一个量级。
再说文件传输。Windows 上传统做法是开 SMB 共享或者架 FTP 服务器,但这两者在公网环境里安全性都不够看,而且配置繁琐。SSH 自带 SFTP 子系统,只要装好 OpenSSH,你就能用任何支持 SFTP 的客户端(FileZilla、WinSCP、甚至命令行 scp)直接传文件,走的是和 SSH 同一套加密通道,不需要额外开放端口。
还有一个场景是密钥登录。Windows 的 OpenSSH 支持公钥认证,你可以生成一对密钥,把公钥放到 Windows 用户的authorized_keys文件里,之后登录就不需要密码了。这对自动化运维来说很重要,脚本里不用硬编码密码,安全性提升很多。
1.2 在线安装与离线安装两条路线怎么选
这个问题的答案取决于你的机器能不能访问互联网。
在线安装适合那些能连通微软更新服务器或者可以访问互联网的开发机、测试机。优点是一条命令装完,自动处理依赖,版本也是最新的。缺点是如果你的内网策略很严格,根本连不出去,那就走不通。
离线安装适合内网服务器、生产环境、还有一些等保要求严格的网络。这些机器一般不能访问外网,只能通过介质拷贝安装文件。离线安装的难点不在于拷贝本身,而在于找对安装包、带上所有依赖、处理安装权限。这两个场景我在实际工作中都踩过不少坑,下面分别把步骤和注意事项讲透。
2. 在线安装OpenSSH:图形界面与命令行双方案
2.1 图形化安装全流程
如果是单台机器,偶尔用一次,图形化方式最直观。
按Win + I打开系统设置,进入“应用” -> “可选功能”,然后点击“添加可选功能”按钮。系统会加载功能列表,这时候在搜索框里输入OpenSSH就能看到结果。列表里一般会出现两个条目:
OpenSSH 客户端:提供ssh、scp、sftp等命令,用来连接其他 SSH 服务。OpenSSH 服务器:提供sshd服务,让其他机器能连到这台 Windows 上来。
如果你只是需要从这台机器去连别人,装客户端就够了;如果你要被别人连,或者打算把 Windows 当作跳板机、文件服务器,那就必须装服务器组件。大多数运维场景下两个都装。
点击“安装”之后等待进度条走完,这个过程根据网络状况和系统负载,一般几十秒到几分钟。装完之后不需要重启,但建议打开 PowerShell 验证一下。
注意:如果你在“可用功能”列表里搜不到 OpenSSH,大概率是系统版本问题。OpenSSH 是 Windows 10 1809 和 Windows Server 2019 开始作为可选功能引入的,如果你的系统是更老的版本,建议直接走 3.2 节的离线方案。
2.2 用PowerShell命令行装更符合运维习惯
图形化安装只适合一台两台,一旦机器数量多起来,或者你打算把安装步骤写进自动化脚本,命令行才是正确的打开方式。
用管理员权限打开 PowerShell,首先可以用一条命令检查系统是否已经内置了 OpenSSH 功能:
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'如果系统还没安装过,输出的状态(State)列会是NotPresent。如果显示Installed,说明之前已经装过了,不需要重复操作。
确认状态之后,安装服务端和客户端各只需一条命令:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0注意命令中的~~~~0.0.1.0是组件版本号,正常执行时不用修改,系统会拉取功能包。执行完如果看到RestartNeeded: False就表示不需要重启,状态已经变成Installed。
我在实际执行这条命令时偶尔会遇到一种情况:网络是通的,但命令运行几分钟后返回一个错误,提示无法从 Windows Update 下载内容。这种情况一般是系统的更新服务(Windows Update)没有启动,或者组策略禁止了 Windows Update 的网络访问。解决办法是在服务管理器里确认Windows Update服务状态为“正在运行”,再重新执行命令。
2.3 在线安装后的基本状态检查
无论用哪种方式安装,安装完成后需要手动启动服务并将服务设置为“自动”启动类型,否则重启机器后sshd不会自动运行。
在管理员 PowerShell 中执行以下命令:
Start-Service sshd Set-Service -Name sshd -StartupType 'Automatic' Get-Service sshd最后一条Get-Service用来确认服务状态,正常情况下Status列会显示Running。
另外可以用ssh localhost做一次本机回环测试,首次连接会提示确认指纹信息,输入yes回车,再输入当前用户的密码。如果能够正常显示 Windows 的命令行提示符,说明服务端基本工作正常。
提示:Windows 默认的 SSH 监听端口是 22,和 Linux 一致。如果系统防火墙没有自动放行 22 端口,外网机器是连不进来的,这点在后面的章节我会详细说明。
3. 无网环境的离线安装方案
3.1 离线安装的核心思路:换台机器取“货”
离线安装的场景我很熟悉,通常是在内网机房里,机器没有外网权限,但你又必须让它提供 SSH 服务。这时候的核心思路就一句话:找一台能上网的机器,把安装包下载下来,然后用 U 盘、内网文件服务器或者远程桌面拷贝等方式,把安装包传到目标机器上。
Windows 的 OpenSSH 离线安装有两种主流途径,一种是从 GitHub 下载 MSI 安装包手工安装,另一种是提取 Windows 自带功能的 cab 包。这里我更推荐第一种,因为 MSI 包是微软官方提供的 OpenSSH for Windows 发行版,安装流程和依赖处理都比较规范,遇到问题的概率小很多。
GitHub 上可以找到微软官方的 OpenSSH for Windows 发布页面,其中.msi后缀的文件就是可用的安装包。文件名一般分为两个部分:OpenSSH-Win64.msi对应 64 位系统,OpenSSH-Win32.msi对应 32 位系统。现代 Windows 基本都是 64 位,直接拿 64 位版本就行。
注意:下载时留意一下版本号和发布时间,尽量选择正式稳定版而不是 RC 候选版。选包的时候也要注意上下载页面的坑,别下成源码包。
3.2 MSI包安装的完整操作与参数说明
打包好的 MSI 拷贝到目标机器上之后,安装过程可以双击完成,但我更推荐用命令行方式,因为能带参数,也方便写进部署脚本。
管理员权限打开 PowerShell 或者 CMD,切换到 MSI 文件所在目录,执行:
msiexec.exe /i OpenSSH-Win64.msi /qn/i表示安装,/qn表示静默模式,全程无界面,安装结束自动退出。如果在安装时还想指定安装路径,可以加INSTALLDIR参数:
msiexec.exe /i OpenSSH-Win64.msi /qn INSTALLDIR="C:\Program Files\OpenSSH"MSI 默认安装路径是C:\Program Files\OpenSSH,一般不用刻意修改,保持默认反而更省事。
安装完成之后有一个关键动作:把C:\Program Files\OpenSSH这个目录加进系统的PATH环境变量。不做这步的话,你开一个命令行窗口敲ssh是找不到命令的。可以用下面这条命令临时添加(当前会话有效):
$env:Path += ";C:\Program Files\OpenSSH"但如果要永久生效,需要在系统属性面板的环境变量里手动加,或者用 PowerShell 把路径写进系统PATH:
[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\OpenSSH", "Machine")3.3 离线下可能踩的坑:依赖与权限
离线安装最大的坑往往不是 MSI 包本身,而是安装前后的环境问题。
第一是安装依赖。如果目标机器缺少Microsoft Visual C++ Redistributable运行库,MSI 安装过程可能报错或者安装了却无法运行。解决办法是下载对应位数的 VC++ Redistributable 离线安装包一起拷过去,先装运行库再装 OpenSSH。判断是否缺少这个依赖,一般安装报错时会直接提示缺少某个VCRUNTIME140.dll之类的文件。
第二是权限问题。安装过程中如果 UAC(用户账户控制)弹窗被系统策略拦截,或者当前用户不是管理员组成员,MSI 执行时会报“安装中止”之类的错误。务必要用管理员身份的 PowerShell 或者 CMD 来跑msiexec命令。
第三是服务注册问题。MSI 安装完成后,sshd服务一般是自动注册的,但少数情况下服务没有注册成功。这时候不用重新安装,可以直接手动注册服务。在管理员 PowerShell 中执行:
cd "C:\Program Files\OpenSSH" powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1这个 PowerShell 脚本会创建sshd和ssh-agent两个服务。之后再确认一下服务是否存在:
Get-Service sshd如果显示不存在,就需要检查安装目录下是否有install-sshd.ps1文件,没有的话说明安装动作并未真正完成。
我还遇到过一种情况:安装包明明是正确的 64 位版本,安装时却提示“系统不支持”。后来发现那台机器装的是精简版系统,被精简掉了不少系统组件。这种环境只能考虑换标准版系统,或者用 32 位版本碰碰运气,但一般不推荐在精简系统上折腾。
4. 安装完成后的关键配置
4.1 服务自启与防火墙放行
装好 OpenSSH 只是第一步,真正让人放心使用的是把服务启停策略和防火墙规则都配好。
服务自启这块,在线安装和离线安装都需要手动设置,因为我见过不少装了 MSI 包之后服务状态正常、但重启就丢失的情况。在管理员 PowerShell 中一次性搞定:
Set-Service -Name sshd -StartupType 'Automatic' Start-Service sshd防火墙放行是另一个容易忽略的点。Windows 默认防火墙会拦截入站的 22 端口流量,即使服务跑起来了,外部机器也连不上。最简单的方法是使用 PowerShell 添加规则:
New-NetFirewallRule -Name "OpenSSH-Server" -DisplayName "OpenSSH Server (sshd)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22这条命令会新建一个入站规则,放行 TCP 22 端口。执行后可以用Get-NetFirewallRule -Name "OpenSSH-Server"确认规则状态。
提示:如果你的 Windows 机器上装了第三方安全软件,比如 360、火绒或者企业版终端管理软件,光是系统防火墙放行还不够,这些软件自带的主防规则也可能拦截 sshd 进程的监听行为。轻则外网连不上,重则 sshd 直接启动失败。遇到这种情况,需要在安全软件里把
sshd.exe加入信任或者放行 22 端口的入站流量。
4.2 用密钥登录替代密码登录
Windows OpenSSH 完全支持公钥认证,但配置方式和 Linux 有一点细节上的差异,很多从 Linux 转过来的运维人员会卡在这里。
首先在客户端机器上生成密钥对。如果本地有 Linux 环境,直接执行ssh-keygen -t ed25519 -C "your_email"即可。如果是在 Windows 的 PowerShell 里生成密钥,就需要先确认 OpenSSH 客户端已经安装好了。生成命令一样:
ssh-keygen -t ed25519 -C "user@host"生成的公钥默认在C:\Users\你的用户名\.ssh\id_ed25519.pub,私钥在id_ed25519。公钥可以分发,私钥绝对不能离开自己的电脑。
然后把公钥内容添加到 Windows 目标机器对应用户的authorized_keys文件里。Windows 下authorized_keys的位置和 Linux 不在同一个路径,它在用户目录的C:\Users\用户名\.ssh\authorized_keys下。添加公钥的命令:
Add-Content $env:USERPROFILE\.ssh\authorized_keys "ssh-ed25519 AAAA... your_public_key"这里有一个非常容易踩坑的点:C:\Users\用户名\.ssh这个目录不一定存在。如果不存在,先用New-Item -ItemType Directory -Path $env:USERPROFILE\.ssh创建目录。
另外,authorized_keys文件必须放在对应用户自己的目录下,不能放在系统管理员共用目录下。比如你用普通用户zhangsan登录,公钥就必须放在C:\Users\zhangsan\.ssh\authorized_keys。
配置完成后,可能还需要处理一下 OpenSSH 的配置。默认情况下 Windows 的 sshd 是允许公钥认证的,但如果你登录的账号是管理员组成员,Windows 默认策略是“仅允许通过公钥认证登录管理员账户”。这句话很多人理解反了,它意思是管理员账号不能用公钥登录,必须用密码登录,除非你在sshd_config里显式加上一句话:
# 文件位置:C:\ProgramData\ssh\sshd_config Match Group administrators AuthorizedKeysFile __PROGRAMDATA__/ssh/administrators_authorized_keys这个默认配置的本意是更安全的锁定管理员登录,但它和很多人心里预期的“有公钥就能登录”冲突。如果不改这个配置,用管理员账号测试密钥登录就会发现一直要密码。
解决办法有两种。最简单的,不用管理员账号登录,新建一个普通 user 账号来用;或者,如果你坚持要管理员密钥登录,就把上面的Match Group administrators那一段的AuthorizedKeysFile改成普通用户的标准路径。但我不推荐第二种,因为会降低安全性,密码加管理员权限的组合反而更稳妥。
4.3 修改端口与多实例的建议
默认的 22 端口在某些内网环境下可能会被安全基线扫描报告问题,等保测出来 22 端口暴露也会算一个风险项。虽然 Windows 上修改默认端口的操作不如 Linux 方便,但还是可以做的。
配置文件位置在C:\ProgramData\ssh\sshd_config。用记事本或者 VS Code 打开这个文件,找到这一行:
#Port 22把注释删掉,把22改成你想要的端口,比如2222:
Port 2222改完保存,然后重启 sshd 服务使配置生效:
Restart-Service sshd注意,该配置文件是全局生效的。如果是单实例使用,改端口就可以了;如果你希望同一台机器上同时监听多个端口,Windows OpenSSH 本身不直接支持,但可以通过注册多个服务实例的方式实现,过程比较麻烦,实际用到的场景也很少,我这里就不展开了。
改完端口后,客户端连接也要指定对应端口:
ssh -p 2222 user@host经验之谈:不要用太冷门的端口,比如 2222 已经快变成公认的默认备选端口了,扫描器都会先扫 22、2222、22022 这些常规位置。如果真要改,选一个 10000+ 的不常用高位端口,配合强密码或者密钥登录。
5. 常见问题与排查实录
5.1 在线安装时提示功能不可用
症状:用Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0安装时报错,提示“无法找到所需的文件”或者“拒绝访问”。
排查思路分两步。
第一步,确定 Windows 更新服务是否可用。检查服务管理器里Windows Update服务状态,手动启动后重试。
第二步,检查系统时间。如果系统时间和真实时间偏差超过几分钟,Windows Update 组件连接微软服务器时会出现证书验证失败,从而导致安装报错。这个问题我很早以前吃过一次大亏,排查到后面才发现是主板电池没电导致时间歪到了十年前。
5.2 离线安装卡在0%或失败
症状:双击 MSI 或者执行msiexec /i OpenSSH-Win64.msi /qn后,界面卡在 0%,或者瞬间退出且没有输出。
如果静默安装时卡住,先尝试去掉/qn参数,改成有界面的安装方式:
msiexec.exe /i OpenSSH-Win64.msi这样能看到安装进度和具体的错误信息。一般常见报错有“需要提升权限”,说明当前不是管理员;“磁盘空间不足”;还有“安装程序被组策略禁用”,检查目标机器是否有碍事的软件分发策略。
另外一个比较隐蔽的坑:如果机器之前已经装过老版本的 OpenSSH MSI,新版本安装可能因为版本回滚规则而被拒绝。解决办法是先卸载旧版本:
msiexec.exe /x OpenSSH-Win64.msi /qn然后再安装新版本。
5.3 服务启动失败:日志在哪看
症状:服务状态是Stopped,手动执行Start-Service sshd报错,提示服务无法启动或者立即停止。
排查这类问题,第一件事是看 Windows 事件查看器。运行eventvwr.msc,展开“Windows 日志” -> “应用程序”,在右侧按事件来源筛选sshd,相关错误日志都会记录在这里。
常见原因是 SSH 配置文件格式出问题。Windows 的sshd_config解析规则比 Linux 严格一点,某些配置项如果写错位置或者格式不对,服务启动就会失败。可以把配置文件里改动过的项先全部注释掉,改成默认状态,再逐步开启,直到找到问题项。
另外一个常见原因是sshd进程需要访问文件系统上的密钥文件,但由于权限问题被拒绝。Windows 的事件查看器会记录类似sshd: PID xxx: error: systemd调用未配置或失败等信息,实际报错会接近Permission denied。这时候检查C:\ProgramData\ssh\目录的权限,确认SYSTEM用户和Administrators组对该目录有完整控制权限。
5.4 安全日志与登录事件分析
Windows 的 OpenSSH 登录行为有自己的审计通道,但很多运维人员不知道从哪里看。
先说登录成功与否。OpenSSH 自身的登录尝试日志会写到事件查看器的“应用程序”日志里,事件来源是sshd。事件 ID 可以参考下表快速定位问题方向。
| 事件类型 | 含义 | 常见原因 |
|---|---|---|
| 提示输入密码 | 服务端要求客户端认证 | 公钥未匹配或密码错误 |
| 身份验证成功 | 登录成功 | 正常事件 |
| 身份验证失败 | 密码错误或密钥不匹配 | 检查密码、公钥 |
| 连接被关闭 | 客户端断开 | 网络中断或认证超时 |
| 不允许使用空密码 | 密码策略限制 | 修改 sshd_config 相关条款 |
如果你还想审计“谁在什么时间通过 SSH 登录过系统”,可以从 Windows 安全日志中查看登录事件 4624(成功登录)和 4625(失败登录)。注意区分,安全日志只记录 Windows 账号的登录行为,未必会和sshd日志一一对应,两者配合查看效果最好。
我自己的习惯是,在 Windows 上搭建一个日志采集,把sshd的应用日志和 4624/4625 安全日志都汇总到中央日志系统,方便事后追溯。如果条件不允许,那至少在sshd_config里开启详细日志:
LogLevel VERBOSE然后重启服务,排查问题时能看到更详细的认证流程日志。
5.5 常见问题速查表
| 问题现象 | 大概率原因 | 处理动作 |
|---|---|---|
| 安装命令找不到模块 | Windows 版本过低或系统精简 | 走离线 MSI 安装 |
| 22 端口外部连不上 | 防火墙拦截 | 添加防火墙入站规则 |
| 公钥登录一直要密码 | 管理员组策略限制 | 新建普通用户或调整 Match Group 配置 |
| sshd 启动后立即退出 | sshd_config 配置错误 | 注释改动项逐步恢复 |
| 服务存在但没启动 | 未设开机自启 | Set-Service 设置 Automatic |
| 从 Linux scp 报错 | 用户名带空格或路径问题 | 加引号处理路径 |
6. 一点个人体会和扩展玩法
Windows 上跑 OpenSSH 这件事,说难不难,说简单也绝对不简单。我最早的几次尝试都卡在配置权限和防火墙这些顺手的事情上,后来总结经验才发现,主要问题不是技术门槛高,而是 Windows 和 Linux 的 SSH 生态在细节上差别很大,比如authorized_keys路径、管理员组策略、防火墙配置方式,每一项都值得单独留意。
如果单位里有条件,我建议在前期就把所有 Windows 机器的补丁版本、系统版本、默认密码策略、公钥体系统一规划好,然后通过 PowerShell 脚本把安装步骤固化下来。真正到了批量部署的时候,一条脚本跑完几十台机器,能省出非常多的时间。
再分享一个自己常用的扩展思路:Windows OpenSSH 装好之后,可以在内网搭一个跳板机,用这台 Windows 机器的 SSH 隧道来访问内网的其他服务。具体操作就是在 Linux 跳板机上执行类似:
ssh -L 8080:内网目标机:80 user@windows跳板机这样一来,内网 Web 控制台可以在本地浏览器直接打开,整个过程都走 SSH 加密隧道,安全性和便利性都很不错。
如果你平时维护的就是 Windows 和 Linux 混合环境,我真心建议把 OpenSSH 的安装和配置流程做成你自己的标准操作手册,至少把在线安装、离线安装、密钥登录这三块吃透。这样无论是日常调试还是紧急排障,你都不会手忙脚乱。