先把结论放在最前面:可以,而且非常可以。Windows Server 2019、2022、Windows 11,甚至 Windows 10 1809 以上的版本,都已经原生内置了 OpenSSH Server 组件,装好之后就能直接用 ssh 客户端登录,做远程管理、跑命令、传文件都没问题。
很多人一听"Windows服务器"就想到远程桌面(RDP),这很正常,毕竟在很长一段时间里Windows的远程管理通道就是RDP。但在混合云、批量运维、自动化部署这些场景里,SSH几乎是绕不开的标准协议。如果你是从Linux切过来维护Windows服务器的朋友,或者你想把Windows服务器纳入统一的自动化管理流程,那这篇文章对你就是刚需。
下面我会从能不能用、怎么安装、怎么配置密钥登录,到实际遇到的问题一个一个讲清楚。所有操作我都实测过,照着抄就行,踩坑点我也会单独标注。
1. 直接回答:Windows服务器可以用SSH登录吗
1.1 为什么你的Windows服务器也该上SSH
有人会问:我远程桌面连上去不也一样吗?敲敲命令、点点鼠标,RDP也够了。这话放在一两台机器上没问题,但一旦机器多了、要批量操作、要接CI/CD流水线,RDP就明显顶不住了。RDP是图形界面会话,不具备脚本化能力,你没法在Jenkins或者GitHub Actions里舒舒服服地调RDP接口,而SSH是标准协议,任何脚本、任何自动化工具都天然支持。
还有一类场景是网络不通RDP但通SSH。很多IDC机房的防火墙策略只放行22端口或者其他业务端口,80、443、22开放,3389反而不开。这种情况下你想管理Windows服务器,SSH几乎是唯一选择。我实际碰到过多次,机器在客户内网,运维口全封死了,只留了跳板机的SSH通道,我就用SSH转发一台Windows管理端来完成维护。
1.2 哪种Windows版本支持SSH
先明确一个大前提:不是所有Windows都能装上官方OpenSSH Server,老掉牙的Windows Server 2008、2008 R2、Windows 7就不要指望系统自带组件了,想用SSH只能装第三方服务端。但从Windows Server 2019和Windows 10 1809开始,OpenSSH相关内容以"按需功能(FOD)"的方式集成在系统里,不需要额外装第三方软件,直接开启就能用。2022、Windows 11就更不用说了,属于标配能力。
这里也顺便回复一下搜索词里经常出现的"esxi如何通过命令行进行ssh链接"。ESXi本身也是通过SSH做命令行管理的,原理和Windows服务器用SSH一样,都是标准SSH协议。本文虽然主要讲Windows,但思路是相通的。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Windows服务器安装OpenSSH Server全流程
2.1 安装前的检查
打开PowerShell(记得用管理员身份),先看系统里有没有这个组件:
powershell复制Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'
如果有返回,说明系统支持,且State字段如果是Installed,那服务已经在了;如果显示NotPresent,就继续下一步安装。
我习惯先查有两个原因:一是避免重复安装,二是有些精简版系统根本没有这个可选功能。如果发现根本没有OpenSSH.Server这个条目,那说明镜像是精简过的,建议换一个完整版系统或者走第三方SSH方案。
2.2 图形界面安装与命令行安装
图形界面方式适合不爱敲命令的人:进入"设置",找到"应用"→"可选功能"→"添加功能",搜索OpenSSH服务器,勾选并安装。装完重启一下sshd服务即可。这种方式胜在直观,但只能一台一台点,不适合批量交付。
企业里批量交付Windows服务器时,我更喜欢用命令行安装:
powershell复制Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
整条命令跑完,组件就装好了。如果需要客户端,那就把上面命令里的Server换成Client,即OpenSSH.Client~~~~0.0.1.0。Windows 10以后的系统默认自带OpenSSH Client,一般不用装,但Server组件很多是默认关闭的,所以安装重点是Server。
2.3 启动服务与确认防火墙
组件装上不代表服务在跑。继续执行:
powershell复制Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
第一条是把服务立即启动,第二条是设置开机自启。如果不设置自启,服务器重启之后SSH就断了,运维时找不到入口,这种教训我踩过好几次。
然后一定要确认防火墙规则。正常情况下,安装OpenSSH Server时会自动创建一条入站规则,允许TCP 22端口。但精简系统、离线安装包、或者某些安全软件清理过规则的环境里,规则可能不存在。保险起见,手动补一条:
powershell复制New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
到这里,最基本的SSH服务已经通了。从你的电脑上试一下:
bash复制ssh administrator@服务器IP
如果让你输密码,说明已经成功。Windows服务器默认用的是本地账号或AD账号,账号名就是你的Windows登录用户名。
3. 把SSH配置成趁手的工具:默认Shell和端口转发
3.1 修改默认Shell为PowerShell
刚连上Windows服务器SSH时,命令行可能长这样:
code复制Microsoft Windows [版本 10.0.17763.737]
(c) 2018 Microsoft Corporation。保留所有权利。
C:\Users\Administrator>
没错,默认shell是CMD。CMD的老毛病大家都知道——处理文本、写复杂脚本都很痛苦。既然都走SSH了,干脆把默认shell换成PowerShell,体验马上不一样。
改法有两种,我推荐注册表方式。在服务器上用管理员PowerShell执行:
powershell复制New-Item -Path "HKLM:\SOFTWARE\OpenSSH" -Force | Out-Null
Set-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name "DefaultShell" -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
改完退出重连,默认就进PowerShell了。注意一下,如果路径写错,SSH连上来会直接闪退,排查时先看DefaultShell值。
改默认shell这件事,很多人忽略,但我觉得是Windows SSH体验的关键一步。CMD里跑PowerShell命令还得先敲powershell,每次都要多一步,自动化脚本里更别扭。换成PowerShell之后,可以顺畅地跑Get-Service、Get-Process、写脚本,和Linux下用bash的体验对上了。
3.2 用SSH隧道访问Windows内网端口
SSH不止能登进去敲命令,还能做端口转发。我在实际运维里经常遇到这种情况:跳板机只能SSH过去,但Windows服务器上的某个Web服务或者SQL Server端口并不想暴露在公网,这时候就可以用本地端口转发,把远程Windows上的服务地址映射到本机localhost。
bash复制ssh -L 1433:localhost:1433 administrator@windows-server
这个命令把Windows服务器上的1433端口(SQL Server默认端口)映射到你本地电脑的1433端口,本地工具连 localhost:1433 就等于连远程数据库。前端调后端接口、本机用SSMS管理远程数据库,都这么玩。
还有个更实用的用法是反向隧道。Windows服务器往外主动连你的运维机器,建立一条隧道,你在本机就能访问Windows服务器的远程管理口。这在公网直连受限、服务器只能出站不能入站的场景里非常救命。命令大概是:
bash复制ssh -R 23389:localhost:3389 user@你的运维机IP
在Windows服务器上执行这条,然后你的运维机器上访问 localhost:23389,就相当于访问Windows服务器的3389端口。注意这只是隧道原理,实际还要配合目标机器的RDP服务才行。
4. SSH密钥登录与安全加固:从密码认证到免密
4.1 生成密钥对与公钥部署
密码登录在少量服务器里够用,但服务器一多,密码管理就是灾难。密钥认证是SSH的标准做法,安全性高,还能免密。步骤如下:
先在本地(也就是你的电脑)生成密钥对:
bash复制ssh-keygen -t ed25519 -C "windows-server-key"
一路回车即可,生成后会得到两个文件:id_ed25519(私钥)和id_ed25519.pub(公钥)。私钥保存在本地,公钥要部署到服务器上。有人问用什么算法,我推荐ed25519,性能好、密钥短、安全强度够;老系统兼容性不好再用RSA 4096。
公钥的部署是Windows上有坑的地方。如果登录的是Windows普通用户,把公钥内容放到服务器上该用户的:
code复制C:\Users\用户名\.ssh\authorized_keys
如果登录的是Administrators组的成员,公钥要放到:
code复制C:\ProgramData\ssh\administrators_authorized_keys
这个文件默认不存在,需要自己创建。而且它必须满足严格的ACL权限,只有SYSTEM和Administrators组有权限才行,否则ssh服务端会拒绝使用这个文件,密钥认证就会失败,表现为连不上或者回退到密码认证。很多朋友密钥登录配不上,十有八九就是卡在这里。
有人纠结为什么管理员要单独用administrators_authorized_keys,因为Windows管理员权限太大,官方为了防止恶意注入公钥提权,就规定需要这个文件配合严格权限校验。
4.2 密钥认证的常见坑
讲几个我实际遇到的密钥认证问题。第一是"生成了公钥也放对位置了,但还是提示要密码"。这种情况多半是administrators_authorized_keys文件的权限不对。解决办法是在服务器上打开文件权限设置,移除继承,只保留SYSTEM和Administrators的完全控制权限。用命令处理的话:
cmd复制icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r
icacls C:\ProgramData\ssh\administrators_authorized_keys /grant "SYSTEM:(F)" "Administrators:(F)"
第二是authorized_keys文件内容格式问题,Windows的ssh服务端对文件格式有要求,最好保存成无BOM的UTF-8格式,别用记事本另存为带BOM的UTF-8,否则解析会出问题。第三是不要往authorized_keys里塞了一堆公钥但没换行,Windows下的配置文件解析比较死板,每个公钥单独一行最稳妥。
4.3 安全加固建议
既然说到了安全,干脆把Windows SSH安全加固一起说了。首先,建议修改sshd_config里的默认配置。配置文件在:
code复制C:\ProgramData\ssh\sshd_config
修改前先备份一份。常用加固项包括:
- 修改默认端口,把22改成高位端口,能挡掉90%以上的随机扫描
- 设置MaxAuthTries 3,失败次数多了自动断开
- 设置AllowUsers,只允许指定账号登录
- 关闭密码认证:把PasswordAuthentication改成no,强制走密钥
- 防火墙层面限制来源IP,只允许运维网段访问22端口
改完配置记得重启sshd服务:
powershell复制Restart-Service sshd
这里要强调一下,ssh连不上影响面很大,所以我都会先开着另一个会话,确认新配置没问题再关掉旧会话。曾经有一次我在服务器上把端口改成了29922,防火墙也放行了,但服务没重启成功,直接导致自己进不去设备间,后来只能让现场同事用本地控制台处理。从那以后我养成了改配置前备份+保持会话的习惯。
5. 实战场景:用VS Code远程连Windows服务器干活
5.1 Remote-SSH插件的配置
SSH配置好以后,最大的便利就是可以把Windows服务器当成开发机来用。VS Code的Remote-SSH插件,相信不少人搜过"vscode连接ssh远程服务器",这套完全适用于Windows服务器。
先在本地安装Remote-SSH插件,然后编辑SSH Config文件,路径一般在用户目录下的.ssh\config,配置内容大概是:
code复制Host win-server
HostName 192.168.1.100
User administrator
Port 22
IdentityFile ~/.ssh/id_ed25519
保存后,在VS Code左下角远程连接入口选"Connect to Host",选择win-server,它就会通过SSH连上Windows服务器,然后在本地打开远程目录。连上以后你可以直接编辑远程文件、打开终端跑PowerShell命令、看日志,体验和本地开发几乎无差别。这个功能对运维排查尤其好用,不用再一层层点远程桌面来回切换窗口。
5.2 配合自动化工具批量管理
如果你管理十几台甚至几十台Windows服务器,一台台连上去敲命令效率太低了。SSH的价值就在于可以通过跳板机批量执行。比如你在Linux跳板机上写一段脚本,循环连Windows服务器执行命令:
bash复制for host in 192.168.1.10 192.168.1.11 192.168.1.12; do
ssh administrator@$host "systeminfo | findstr /C:\"OS Name\""
done
这样就能批量收集Windows服务器版本信息。再配合scp或者sftp,可以批量下发文件、更新脚本。我做过一个Windows集群的巡检,全部靠SSH批量跑PowerShell命令,把CPU、内存、磁盘、服务状态汇总到表格里,比手工一台台RDP进去点快几十倍。
另外,GitHub Actions和Jenkins里也支持通过SSH执行远程命令。比如前端项目构建后,通过SSH把产物传送到Windows服务器上的IIS目录,再执行重启站点命令,一套自动化发布流程就出来了。Windows服务器在现代DevOps体系里完全不是异类,前提是好好把SSH通道用起来。
6. 常见问题与排查实录
6.1 问题速查表
我把日常遇到的高频问题整理成了一张表,方便检索。
| 问题现象 | 最常见原因 | 解决办法 |
|---|---|---|
| Connection refused 连接拒绝 | sshd服务未启动 | 管理端PowerShell执行Start-Service sshd |
| 连接超时 | 防火墙未放行22端口 | 检查并创建防火墙规则,确认端口和协议 |
| 能连上但闪退 | DefaultShell路径错误 | 检查注册表SOFTWARE\OpenSSH下的DefaultShell值 |
| 密码认证失败 | 账号名写错或密码过期 | 确认Windows账号密码,策略要求改密时先改密码 |
| 密钥认证回退到密码 | administrators_authorized_keys权限不对 | 执行icacls命令重置ACL,只保留SYSTEM和Administrators |
| 端口已被占用 | 服务器的22端口被其他服务占用 | 用netstat -ano | findstr :22找出PID,改sshd_config端口 |
| SSH输出中文乱码 | 控制台代码页不一致 | 在PowerShell里执行chcp 65001切换UTF-8 |
这些错误基本覆盖了你刚入手Windows SSH时的绝大多数问题。
6.2 我的排查顺序
最后分享一套我屡试不爽的排查顺序。连接失败时,不要一上来就怀疑OpenSSH配置,按下面顺序一步步来:
第一步查服务。在服务器本地控制台或远程桌面里执行Get-Service sshd,如果ServiceStatus不是Running,先启动再说。
第二步查端口。netstat -ano | findstr :22,看看22端口有没有在监听。如果没监听,服务可能启动失败了,去事件查看器里找OpenSSH相关的错误日志。
第三步查防火墙。如果服务在跑端口也在听,但你从外部连不通,90%是防火墙拦截。检查入站规则里sshd规则是否存在,状态是否Enabled,本地端口是否为22。
第四步查客户端侧。在你本地执行```bash
ssh -vvv user@ip
,打开调试模式,看输出卡在哪一步。是TCP层不通,还是认证阶段报错,还是协议握手失败,日志会说得明明白白。复制
第五步查权限。如果是密钥认证失败,回到4.2节,检查authorized_keys文件位置和权限。注意服务端日志,位置一般在C:\ProgramData\ssh\logs,里面会写明公钥校验被拒绝的具体原因。
按照这套顺序排查,绝大部分问题十分钟内能定位。
最后再分享一个我个人的小习惯。我并不会只依赖远程桌面来管Windows服务器,现在很多临时性操作、检查、日志查看都在终端里完成。建议你也从今天开始,把SSH当作Windows服务器的第二管理通道,哪怕只是每天连上去看一眼服务状态,也比每次都开远程桌面轻量得多。等真正遇到批量操作和网络受限的时候,你会感谢当初配好的这套SSH环境。
