在 Windows 上配置 SSH Key 认证(只允许 Key 登录)
这篇文章记录了在 Windows 上配置 SSH key 认证的完整过程。作为一个从 Linux 过来的用户,Windows 的 OpenSSH 和 Linux 行为有几个很坑的差异,踩坑之后特此记录…
整体目标
从 Ubuntu(或其他远程主机)通过 SSH key 连接到 Windows 机器,不使用密码。具体要求:
- Windows 开启 OpenSSH Server
- 自定义端口(本文以
2333为例) - 禁用密码登录,只允许 SSH key
- 路由器配置端口转发(家用网络必须)
第一步:安装 OpenSSH Server
首先,用管理员身份打开 PowerShell(右键 → 以管理员身份运行),然后检查是否已安装:
Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Server*'
⚠️ 注意:这个命令必须用管理员权限运行,普通用户会报”请求的操作需要提升”的错误。
如果显示 State : NotPresent,执行安装:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
安装完成后确认状态变为 State : Installed。安装过程大概需要5到15分钟, 或更多不等,请耐心等待。
如果命令行安装卡住,也可以通过图形界面安装:设置 → 应用 → 可选功能 → 添加功能 → 搜索 “OpenSSH Server”。
第二步:启动 SSH 服务
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic
服务启动后,配置文件才会生成。注意 C:\ProgramData 是隐藏目录,在文件管理器地址栏直接输入路径 C:\ProgramData\ssh 回车即可进入。
第三步:修改 SSH 配置
编辑配置文件(需要管理员权限):
C:\ProgramData\ssh\sshd_config
添加或修改以下内容:
Port 2333
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication no
AuthorizedKeysFile .ssh/authorized_keys
建议删除重复的
AuthorizedKeysFile行(Windows 默认配置文件里有时会有两行)。
第四步:放行防火墙端口
Windows 不会自动为新端口添加防火墙规则,需要手动添加:
New-NetFirewallRule -Name sshd-2333 `
-DisplayName "OpenSSH Server (2333)" `
-Enabled True `
-Direction Inbound `
-Protocol TCP `
-Action Allow `
-LocalPort 2333
第五步:添加公钥
生成 SSH key(在 Ubuntu/客户端机器上)
如果还没有 SSH key:
ssh-keygen -t rsa -b 4096 -f ~/.ssh/kth_id_rsa
查看公钥内容:
cat ~/.ssh/kth_id_rsa.pub
把公钥放到 Windows
这里有一个 Windows OpenSSH 特有的大坑,和 Linux 不同:
如果你的 Windows 用户属于 Administrators 组(即使是 deny-only),OpenSSH 不会读取 C:\Users\<用户名>\.ssh\authorized_keys,而是优先读取:
C:\ProgramData\ssh\administrators_authorized_keys
你可以通过以下命令确认自己是否在 Administrators 组:
whoami /groups
如果看到 BUILTIN\Administrators(无论什么属性),建议把公钥放到这个路径:
C:\ProgramData\ssh\administrators_authorized_keys
把 Ubuntu 上的公钥内容(kth_id_rsa.pub 的内容,一整行)粘贴进这个文件。
设置权限(非常关键)
Windows OpenSSH 对文件权限非常严格,权限不对 key 会被直接忽略:
# 针对管理员的 authorized_keys 文件
icacls C:\ProgramData\ssh\administrators_authorized_keys /inheritance:r
icacls C:\ProgramData\ssh\administrators_authorized_keys /grant SYSTEM:F
icacls C:\ProgramData\ssh\administrators_authorized_keys /grant Administrators:F
如果你是普通用户(不在 Administrators 组),文件放 C:\Users\你的用户名\.ssh\authorized_keys,权限这样设:
icacls C:\Users\Kin\.ssh /inheritance:r
icacls C:\Users\Kin\.ssh /grant Kin:F
icacls C:\Users\Kin\.ssh /grant SYSTEM:F
icacls C:\Users\Kin\.ssh\authorized_keys /inheritance:r
icacls C:\Users\Kin\.ssh\authorized_keys /grant Kin:F
icacls C:\Users\Kin\.ssh\authorized_keys /grant SYSTEM:F
⚠️ 修改
.ssh目录权限时要小心,权限改坏了会导致你连”ssh 出去”都失败。如果出问题,用icacls ... /reset重置。
第六步:重启 SSH 服务
Restart-Service sshd
第七步:路由器端口转发(家用网络必须)
如果你的 Windows 机器在家用网络下(IP 类似 192.168.x.x),公网 IP 属于路由器,外部连接会被路由器挡住。
检查方法:
netstat -ano | findstr 2333
如果看到类似 192.168.1.100:2333,说明是内网 IP,需要在路由器后台(通常是 192.168.1.1)添加端口转发规则:
| 外部端口 | 内网 IP | 内网端口 | 协议 |
|---|---|---|---|
| 2333 | 192.168.1.100 | 2333 | TCP |
Check a detailed example in my other blog post.
第八步:测试连接
在 Ubuntu(客户端)上测试:
ssh -p 2333 -i ~/.ssh/kth_id_rsa Kin@你的公网IP
成功的话应该直接进入 Windows 的 shell,不会提示输入密码。
为了方便,可以在 Ubuntu 的 ~/.ssh/config 里配置别名:
Host win
HostName 你的公网IP
Port 2333
User Kin
IdentityFile ~/.ssh/kth_id_rsa
之后直接 ssh win 即可。
常见问题排查
问题 1:连接卡住(Connecting to … port 2333,无后续)
说明端口没通,不是认证问题。检查:
- Windows 防火墙是否放行了 2333
- 路由器是否配置了端口转发
-
netstat -ano | findstr 2333确认 sshd 确实在监听
问题 2:Permission denied (publickey)
说明 key 发出去了,但服务器拒绝了。检查:
- 公钥是否放到了正确路径(见上文关于管理员路径的说明)
- 文件权限是否正确(icacls 设置)
-
authorized_keys文件内容是否完整(一整行,不能断行) - 文件编码是否正确(用记事本保存可能引入 BOM)——建议用 PowerShell 写入:
(Get-Content C:\ProgramData\ssh\administrators_authorized_keys) | Set-Content -Encoding ascii C:\ProgramData\ssh\administrators_authorized_keys
- 查看 OpenSSH 日志,定位具体原因:
Get-WinEvent -LogName "OpenSSH/Operational" -MaxEvents 20
问题 3:Connection closed by authenticating user [preauth]
这通常说明 sshd 根本没有进入验证密钥的阶段。最常见原因是公钥放错了路径——请确认你的用户是否在 Administrators 组,然后把公钥放到对应的正确路径。
问题 4:修改了 .ssh 权限后,自己连不上其他主机了
.ssh 目录不只是服务端用,SSH 客户端也依赖里面的 id_rsa、known_hosts 等文件。权限过严会导致客户端也无法使用 key。恢复方法:
icacls C:\Users\Kin\.ssh /reset
icacls C:\Users\Kin\.ssh /grant Kin:F
icacls C:\Users\Kin\.ssh /grant SYSTEM:F
icacls C:\Users\Kin\.ssh /grant Administrators:F
SSH 端口转发(-L)的一个经典坑
如果你用 SSH 端口转发(如访问 Windows 上的某个服务),命令写法很重要:
有问题的写法:
ssh -L 2053:localhost:2053 -p 2333 Kin@你的IP
推荐写法:
ssh -L 2053:127.0.0.1:2053 -p 2333 Kin@你的IP
原因:在 Windows 上,localhost 可能被解析为 IPv6 的 ::1,而很多服务只监听 IPv4 的 127.0.0.1,导致端口转发建立了但访问不通。显式写 127.0.0.1 可以绕过这个问题。
验证方法:在 Windows 上 ping localhost,如果结果是 ::1 就说明默认走 IPv6。
Windows SSH 与 Linux 的关键区别总结
| 项目 | Linux | Windows |
|---|---|---|
| authorized_keys 路径(普通用户) | ~/.ssh/authorized_keys | C:\Users\<user>\.ssh\authorized_keys |
| authorized_keys 路径(管理员用户) | 同上 | C:\ProgramData\ssh\administrators_authorized_keys |
| 权限要求 | 宽松 | 严格,权限不对直接拒绝 |
localhost 解析 | 通常是 IPv4 | 可能是 IPv6(::1) |
| 配置文件 | /etc/ssh/sshd_config | C:\ProgramData\ssh\sshd_config |
最终安全配置建议
Port 2333
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
MaxAuthTries 3
AllowUsers Kin
AuthorizedKeysFile .ssh/authorized_keys
这套配置禁用密码、限制尝试次数、只允许指定用户登录,已经是比较安全的基础配置了。
Enjoy Reading This Article?
Here are some more articles you might like to read next: