简介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.zipWindows 上手工部署 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 yourname192.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这个小小的包能把复杂度收敛到可管理的范围前提是每一步按顺序来特别是权限修正的部分跳过哪一步都会在后面以奇怪的方式反弹回来。希望这篇笔记能帮你少踩几个我已经踩过的坑。本文还有配套的精品资源点击获取