简介:OpenSSH-Win64.zip 是面向 Windows 的 OpenSSH 64 位工具包,为开发、运维人员在 Windows 下进行 SSH 远程登录、命令执行与文件传输提供支持,弥补系统自带功能不足。压缩包共 29 个文件,约 4.86MB,主要包含 13 个可执行程序、4 个 PowerShell 脚本、2 个 JSON 配置、2 个文本文件,以及动态库、默认配置和校验文件等;可执行程序覆盖客户端、服务端、密钥生成与文件传输,PowerShell 脚本用于安装、卸载和权限修复,结构清晰便于部署。已有 801 人学习下载。该压缩包可在 Windows 上快速搭建 SSH 服务,实现安全的远程命令行管理和文件传输,并附带密钥生成、权限修正和完整性校验,适合需要自管 SSH 的运维人员。
1. OpenSSH-Win64.zip:Windows 上手工部署 SSH 的绿色通道
拿到一个OpenSSH-Win64.zip,很多人第一反应是「Windows 不是自带 OpenSSH 了吗,为什么还要解压一个 zip 包来用?」实际上,Windows 10/11 自带的 OpenSSH 属于「可选功能」,非企业版系统默认不开装,而且它的更新节奏跟着系统补丁走,版本常年落后。更关键的是,当你需要在内网离线环境、批量部署到几十台服务器、或者想用一个固定版本来统一行为时,系统自带的那个组件反而不好管。这个 zip 包就是 Win32-OpenSSH 社区发布的预编译二进制集合,解压即用,不写注册表、不动系统组件,装错了删掉重来就行。它解决的核心问题就一句话:在 Windows 上拿到一个版本可控、路径随我、卸载干净的 SSH 客户端和服务端。本文面向需要自己维护 Windows 主机间安全远程连接的运维和开发,照下面的步骤,十分钟内能把这套东西跑起来。
2. 为什么选 zip 版而不是系统自带:先分清三个来源
2.1 Windows 自带 OpenSSH 与独立 zip 包的差别
Windows 上的 SSH 工具有三条来历。第一条是 Windows 10 1809 之后系统内置的可选功能「OpenSSH 客户端」和「OpenSSH 服务端」,在「设置 → 可选功能」里安装,优点是开箱即用,缺点是二进制混在系统目录里,你拿不到一个干净的可迁移文件。第二条是 Git for Windows 自带的 ssh.exe,路径通常在C:\Program Files\Git\usr\bin\ssh.exe,但这个版本依赖 Git 的运行时环境,单独拷到别的机器上经常缺 DLL。第三条就是 Win32-OpenSSH 项目发布的 zip 包,即OpenSSH-Win64.zip,它是微软官方参与维护的、面向 Windows 的原生移植版,二进制直接调用 Windows API,不依赖额外的运行时。
三者之间的关系不是互斥的。系统可选的 OpenSSH 服务端和 zip 包里的 sshd 如果同时启动,会因为抢 22 端口而互相踩踏。所以我一般在生产环境里做如下分工:日常工作机的 SSH 客户端用系统自带或者 zip 包的都行,但凡是需要长期稳定监听 22 端口的服务器,统一用 zip 包部署并固定版本,系统自带的那个服务保持「已禁用」状态,避免下次系统更新把它激活造成端口冲突。
2.2 下载、校验与解压:三个关键动作
从发布页获取OpenSSH-Win64.zip之后,不要急着解压,先看三个东西。第一,看版本号,zip 包文件名里通常带版本标签,选一个经过一段时间验证的稳定版,不要追最新;第二,看校验值,发布页一般提供哈希值,用 PowerShell 的Get-FileHash对一下,防止下载过程中文件损坏或被替换;第三,看解压目标路径,Windows 上 OpenSSH 对路径中的空格处理比较宽容,但为了避免后续脚本转义问题,我习惯把它放在C:\OpenSSH这类无空格的路径下。
解压后的目录结构需要心里有数。sshd.exe是服务端主程序,ssh.exe是客户端主程序,ssh-keygen.exe负责生成密钥对,ssh-agent.exe和ssh-add.exe配合做密钥代理,sftp.exe和scp.exe负责文件传输。还有两个 PowerShell 脚本Install-SSHd.ps1和Uninstall-SSHd.ps1,前者把 sshd 注册成 Windows 服务,后者反向卸载。命令行直接进入解压目录操作即可,短会话不需要加 PATH,但如果你希望全局能用,往下看环境变量的配置方法。
# 在解压目录内确认核心二进制存在 cd C:\OpenSSH Get-ChildItem .\*.exe | Select-Object Name, Length上面的命令会列出目录下的所有可执行文件。Name列显示文件名,Length列显示字节数,如果文件大小明显异常或者某个文件缺失,说明 zip 包不完整。正常的 Win64 发行包解压后,ssh.exe和sshd.exe至少应该各有一个,大小在 200KB 到 1MB 之间,具体会因版本不同有浮动,但不会出现只有几 KB 的情况。这里有个小细节:压缩包在 Windows 上解压时,可能因为安全软件拦截导致个别文件没释放全,所以解压后做一个完整性检查是值得养成的习惯。
3. 用 zip 包跑通 SSH 客户端:环境变量、密钥生成与指纹验证
3.1 目录规划与 PATH 环境变量配置
把OpenSSH-Win64.zip解压到C:\OpenSSH后,想让ssh命令在任意路径下都能调用,最直接的方式是把这个目录加进用户或者系统的 PATH。我一般加用户级 PATH,不动系统变量,这样多用户共用一台机器时不会互相影响,也降低了误改系统环境的概率。加完后重启一个新的 PowerShell 窗口,ssh -V应该能输出版本号。
# 将 C:\OpenSSH 追加到用户 PATH(无空格路径,省事) [Environment]::SetEnvironmentVariable( "Path", [Environment]::GetEnvironmentVariable("Path", "User") + ";C:\OpenSSH", "User" ) # 验证 ssh -V这里SetEnvironmentVariable的第三个参数"User"表示作用域为用户级,只需要普通权限。如果在系统服务里跑 sshd,服务进程读的是系统级 PATH,所以服务端相关的配置不依赖这一步。验证用的ssh -V输出一行类似OpenSSH_for_Windows_...的版本信息,注意区分:ssh -V是小写 V,输出版本号;ssh -v是大写 V,输出连接调试日志,两个是完全不同的东西,搞混了会看不懂输出。
3.2 密钥对生成与 authorized_keys 的目录规范
在 Windows 上用 OpenSSH 做免密登录,密钥生成的步骤和 Linux 上一样,但有三个 Windows 特有的坑:家目录识别、权限继承、换行符。第一个坑最隐蔽,OpenSSH for Windows 默认把%USERPROFILE%当作用户的家目录,如果你的用户名是管理员且启用了用户账户控制,实际路径可能是C:\Users\Administrator,但通过 SSH 登录时解析出来的家目录不一定和你预想的一致,建议先执行下面的 PowerShell 确认当前用户的实际家目录路径,再决定密钥放哪里。
# 确认用户家目录(决定 .ssh 放哪) $env:USERPROFILE Get-ChildItem "$env:USERPROFILE\.ssh" -ErrorAction SilentlyContinue生成密钥时我一般用 Ed25519,如果目标机器上的 OpenSSH 版本较老,再退回 RSA 4096。命令如下:
# 在客户端生成 ed25519 密钥对,保存到用户 .ssh 目录 ssh-keygen -t ed25519 -C "win-client-key" -f "$env:USERPROFILE\.ssh\id_ed25519" -N ""-t指定算法,-C是注释,用来识别这把钥匙是哪台设备上的,多台机器时有助于排查。-f指定输出路径和文件名,生成两个文件:不带后缀的id_ed25519是私钥,带.pub后缀的是公钥。-N ""表示空口令,即不设置 passphrase,这样自动化脚本能直接使用;如果是人工操作且私钥泄露面较大,建议去掉-N "",让命令交互式提示输入口令。生产环境我个人坚持所有非交互用途的私钥都不设置 passphrase,但私钥文件的 ACL 一定锁死,只允许当前用户读取。
3.3 第一条 SSH 连接与主机指纹逻辑
服务端启动后(下一章讲),客户端发起连接时会遇到一个交互确认:是否信任服务端的主机指纹。Windows 默认没有 known_hosts 文件,第一次连接必然出现这个提示。这个环节值得多说一句:指纹验证是 SSH 防中间人攻击的第一道屏障,生产环境严禁直接敲 yes 跳过。要求客户端先手工拿服务器端的主机公钥指纹,再在确认一致后输入 yes。
# 连接远程主机(按实际 IP 场景替换) ssh yourname@192.168.6.21 -p 2222 -i "$env:USERPROFILE\.ssh\id_ed25519"参数里-p 2222指定端口,如果服务端没有改端口,这条参数可以省略;-i指定私钥路径。连接失败时优先加-v重新执行,观察输出里debug1:开头的日志。这里补一个小常识:拿到一台新 Windows 服务器时,第一件事要检查的不是防火墙,而是该机器的系统时间是否正确,NTP 偏差超过几分钟会让密钥认证阶段报奇怪的错误。
4. 把 SSH 服务端跑成 Windows 服务:最小安装与参数调优
4.1 安装脚本与首次启动的完整命令序列
要让 Windows 主机成为被连接的 SSH 服务器,处理流程是:解压、装服务、放行防火墙、设置权限、启动。在解压目录里以管理员身份打开 PowerShell,按顺序执行下面的命令。注意这个顺序不是随便排的,每一步的输入依赖前面一步的输出,尤其是「先装服务再配权限」这个次序,装服务之后系统会创建名为sshd的虚拟账户,后续很多权限配置要挂在它名下。
# 第一步:以管理员身份在解压目录中执行安装脚本 cd C:\OpenSSH powershell.exe -ExecutionPolicy Bypass -File .\install-sshd.ps1 # 第二步:将服务设为自动启动,并启动服务 Set-Service sshd -StartupType Automatic Start-Service sshd # 第三步:查看服务状态 Get-Service sshd第一行里-ExecutionPolicy Bypass是为了绕过脚本执行策略的限制,注意这个 bypass 只对本条命令生效,不会改系统策略。第二行Set-Service设置启动类型,如果你不希望开机自启,把Automatic改成Manual,需要时再手动Start-Service sshd。第三行的Get-Service sshd应该显示Running,如果显示Stopped就直接去第五章节找原因,那是最常见的错误场景。
4.2 防火墙放行与服务账户小知识
OpenSSH for Windows 的安装脚本不会自动添加防火墙规则,这是和 Linux 发行版最大的体验差异。装完服务后必须手工放行端口,否则从其他机器连过来时连接会卡在超时状态,服务端本地的 sshd 日志里也看不到任何东西,是排查阶段最容易感到「玄学」的一环。
# 放行 SSH 默认端口 22,这是服务端可用的前提 New-NetFirewallRule -Name "OpenSSH-Server-In" ` -DisplayName "OpenSSH Server (sshd)" ` -Enabled True -Direction Inbound ` -Protocol TCP -Action Allow ` -LocalPort 22这条命令在 Windows Server 2016/2019 以及 Windows 10/11 上都能用。-Direction Inbound表示入站规则,-Protocol TCP限定协议,-LocalPort 22对应监听端口。如果以后服务端改了端口,需要先把这条旧规则删掉,再按新端口重建,不要试图改现有规则的端口属性,因为涉及配置的链路较深,重构更安全。SSH 服务默认以本地系统账户运行,监听 22 端口不需要额外授权。
4.3 首次用密码登录:验证体系有没有通
服务端起来、防火墙也放行之后,用客户端首次连接时建议先用密码登录,目的是先验证 TCP 链路和 SSH 协议解析正常,再上密钥认证。密码登录成功后,下一步是配置密钥登录,这也是最容易被 Windows 坑到的地方——C:\Users\用户名\.ssh\authorized_keys文件的权限如果不对,sshd 会直接忽略这个文件,表现为客户端拿着正确的私钥也登不进去,服务端日志里常见的提示是"Authentication refused"。
# 在服务端:把客户端的公钥内容写入 authorized_keys Add-Content -Path "$env:USERPROFILE\.ssh\authorized_keys" ` -Value "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIxxxxxx win-client-key" # 修正权限:icacls 是 Windows 下调整 ACL 的标准工具 $keyFile = "$env:USERPROFILE\.ssh\authorized_keys" icacls $keyFile /inheritance:r icacls $keyFile /grant:r "$($env:USERNAME):F" icacls "$env:USERPROFILE\.ssh" /grant:r "$($env:USERNAME):F"/inheritance:r会移除从父目录继承来的所有权限,这一步特别重要,因为 Windows 的用户目录默认给 Authenticated Users 等组分配了读取权限,sshd 出于安全考虑会拒绝权限过宽的公钥文件。/grant:r中:r表示替换该用户已有的权限,F表示完全控制。执行完上面的三条 icacls 后,再次从客户端用-i指定私钥连接,如果能登入,说明密钥链路已经打通。
5. 常见问题与避坑:权限、端口、路径三大硬伤
5.1 公钥文件权限错误:服务端静默拒绝密钥认证
现象:客户端指定了正确的私钥文件,服务端也配置了对应的公钥,但连接始终提示输入密码,甚至直接Permission denied。查看服务端日志(事件查看器 → Windows 日志 → 应用程序,来源为 OpenSSHd)时看到类似Authentication refused: bad ownership or modes的条目。
原因:Windows 上authorized_keys文件的 ACL 继承了用户目录的宽松权限,导致 SYSTEM 账户之外的其他账户也能读取该文件。sshd 的安全模型要求公钥文件只能被对应用户和 SYSTEM 修改,权限一旦过宽就直接拒绝使用这个文件。
解决:用icacls清掉继承权限,只给当前用户完全控制权。具体命令就是上一章节的三条icacls,注意执行顺序是「先清继承、再逐级授权」。这个问题的隐蔽性在于「服务端拒绝」不等价于「连接报错」,表现更像「密钥没生效」,容易让人误判成客户端问题。这里有一个深刻的坑:如果你是用管理员账户登录后再通过 SSH 连接本机,路径会受用户账户控制重定向影响,$env:USERPROFILE解析出的路径可能不是实际的 Administrator 配置目录。经验法则:一律用$env:USERPROFILE输出后实际确认一次路径再操作,不要凭脑中的路径假设去拼命令。
5.2 端口被占用或服务起不来:22 端口真不是只属于你
现象:Start-Service sshd执行后,服务状态在「启动中」和「已停止」之间反复,最终停在Stopped。事件日志中记录的是地址已在使用的异常。
原因:最常见的原因是系统自带的 OpenSSH Server 可选功能已经被开启,它的 sshd 进程已经监听了 22 端口。另一种情况是其他应用(比如某些数据库管理工具的端口转发)占用了 22。检查用下面的命令,看 PID 对应的进程是什么。
# 查看当前谁在听 22 端口 netstat -ano | findstr :22解决:如果确认是系统自带的 sshd 在监听,在「设置 → 可选功能」里卸载 OpenSSH 服务端,或者在服务管理器里找到OpenSSH SSH Server并设为禁用,然后重启机器或者直接停掉该服务。如果确认是其他非 SSH 程序占用,两种选择:把占用程序的端口改掉,或者修改本方案中的 sshd 监听端口(见第 6 章配置示例)。改端口是更稳妥的做法,毕竟内网环境普遍没有明确要求必须用 22。
5.3 安装脚本执行遭遇的执行策略和路径空格问题
现象:执行install-sshd.ps1时报错,提示脚本因为系统执行策略而被禁止运行,或者脚本跑了一半提示找不到sshd.exe。
原因:前者是 PowerShell 默认的Restricted执行策略拦截所有脚本,后者是解压路径包含空格或中文字符,导致脚本内部相对路径解析失败。install-sshd.ps1在编写时假设当前工作目录就是解压目录,如果你从别的目录跳到脚本所在目录去执行,相对路径就会错乱。
解决:第一类问题用-ExecutionPolicy Bypass参数绕过,不需要修改系统全局策略。第二类问题,养成「先cd到解压目录再执行脚本」的习惯,不要用./install-sshd.ps1的相对拼写去跨目录调用。如果你一定要把OpenSSH-Win64.zip解压到带空格的路径,比如C:\Program Files\OpenSSH,那就要承受脚本内路径被空格截断的风险,这也是我从一开始就建议C:\OpenSSH的原因。空路径爱好者往往会撞上一堵无形的墙,这不是技术文档能写全的。
5.4 公钥内容格式错误:粘贴时引入人工误差
现象:密钥配置完成后依然无法免密登录,反复检查路径和权限都没问题,最终的定位结果是文件内容不对。原因:多数人复制公钥时,用记事本打开.pub文件后全选复制,结果把换行符、制表符一起复制进去,或者文本编辑器多加了逻辑换行。authorized_keys是一行一个公钥,内容里任何多余的换行都会导致解析失败。解决:在 PowerShell 里直接用命令读取公钥内容并写入目标文件,不要经过记事本中转。
# 从客户端读取公钥内容(一条命令完成,避免手工复制粘贴) Get-Content "$env:USERPROFILE\.ssh\id_ed25519.pub" | Set-Content ` -Path "$env:USERPROFILE\.ssh\authorized_keys" -Encoding asciiSet-Content的-Encoding ascii值得注意,默认的 UTF-8 编码在部分 Windows OpenSSH 版本上会在文件开头写入 BOM 标记,BOM 的存在会让第一行公钥解析失败。坚持ascii编码可以绕开这个历史上踩过的坑。
6. 进阶:用配置文件固化行为
跑通了基本连接,接下来要做的不是收工,而是把行为固化下来。配置文件sshd_config是 OpenSSH 服务端唯一的核心配置文件。解压后默认存在,路径为安装目录下的sshd_config,其默认配置有多处不适合生产。本章给出一份适合 Windows 环境的最小强化配置,并解释每一行的意图。
默认配置中,Subsystem sftp的一行如果写成注释状态会导致 SFTP 连接报错。因此第一步要确认它。下面是一份以端口、认证、协议限制为三条主线的配置示例。修改配置前先备份原文件,命名的规律是带日期后缀。
# 备份原配置(Windows 命令行窗口执行) copy C:\OpenSSH\sshd_config C:\OpenSSH\sshd_config.bak.20240916备份完成后,用记事本打开sshd_config,定位到以下字段并确认或修改:
Port 22022 PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys Subsystem sftp sftp-server.exe第一行Port 22022表示改变默认监听端口,建议改为 1024 到 65535 之间的一个高位端口。改端口有两个好处:避免和系统自带 sshd 或其他软件冲突,同时减少被自动化扫描引擎盯上的概率。第二行PermitRootLogin no在 Windows 上对应的是禁用内置管理员账户的登录,防止那些名字叫 Administrator 的账户直接用密码甚至空密码撞进来。第三行PasswordAuthentication no表示禁用密码登录,只允许密钥认证,这是整个安全加固里最值钱的一条配置。第四行PubkeyAuthentication yes是允许公钥认证,默认为 yes,写在这里是为了强调依赖关系。第五行AuthorizedKeysFile明确公钥文件查找路径,保持默认即可,这个写死路径的做法方便排查。第六行确认 SFTP 子系统指向sftp-server.exe,这个二进制在解压目录里与sshd.exe同级。
配置改完后重启服务使配置生效:
# 重启 sshd 服务让配置生效 Restart-Service sshd # 验证新端口是否监听 netstat -ano | findstr 22022验证时有几个现象供参考。netstat里出现 22022 的监听记录,说明端口换成功了。从客户端连的时候要加上-p 22022,否则默认连 22 端口会得到超时或者拒绝。如果PasswordAuthentication no配置后才发现某个用户确实需要密码登录,不要急着把配置改回去,更好的做法是给该用户也生成密钥对,把公钥放进authorized_keys。整个配置体系里我最后想强调的一点是:每次改完sshd_config,一定要重启服务,部分旧版本的 sshd 不会热加载配置,改完不重启等于白改,且这个行为在不同版本间并不一致,不能靠猜。
这些年维护 Windows 上的 SSH 服务,最大的教训是不要把它当成 Linux 的简单平移。Windows 的权限模型、服务账户、路径解析和事件日志,每一项都有自己独立的脾气。OpenSSH-Win64.zip这个小小的包能把复杂度收敛到可管理的范围,前提是每一步按顺序来,特别是权限修正的部分,跳过哪一步都会在后面以奇怪的方式反弹回来。希望这篇笔记能帮你少踩几个我已经踩过的坑。
本文还有配套的精品资源,点击获取