Windows 上搭建 SFTP 服务:OpenSSH 配置、权限隔离与排错实战 📅 发布时间:2026/9/18 10:14:45 👁 浏览次数: 最近在帮团队搭文件传输服务需求很直接让外部合作伙伴能上传、下载文件数据要加密权限要可控。评估了一圈FTP 明文直接淘汰FTPS 又要单独维护证书最后锁定了 SFTP——它走的还是 SSH 那套加密通道Windows 11 和 Windows Server 2016 以上版本都能通过 OpenSSH 搭建省去一堆额外的加密传输组件。这篇文章把我在 Windows 上配置 SSH/SFTP 的完整过程、配置文件里的每一个关键项、以及权限和排错的坑都写出来希望能帮到打算在 Windows 环境里跑 SFTP 的同行。先给结论无论你用的是 Windows 11 桌面机还是 Windows Server 2016/2019/2022 服务器只要把 SSH 服务端搭起来、放行防火墙、创建好专用账号SFTP 就能直接用。难点从来不在“开 22 端口”这一步而是在用户目录限制、文件权限这些细节上——Windows 的权限模型和 Linux 差很多很多照着 Linux 教程操作的人最后都卡在这里。1. 为什么选 SFTP场景、协议特点与 Windows 上的方案选型1.1 企业文件交换最常见的三个方案给外部用户开文件通道市面上常见的无非三种传统 FTP、基于 SSL/TLS 的 FTPS、以及基于 SSH 的 SFTP。传统 FTP 现在真的不太建议碰。它最大的问题就是用户名、密码、数据全部明文传输抓包工具一抓全暴露。而且 FTP 有主动模式、被动模式之分在内网穿透、云防火墙环境里经常出现能登录但列不出目录的问题。我在早期项目里被 FTP 的 PASV 模式折腾过很多次换了公网 IP 段就会有一堆客户端连不上。FTPS 比 FTP 安全但它依赖证书体系要给服务端配证书、维护 CA 链有些客户端还要关掉证书校验才能连管理成本不低。如果你只是想要一个“开箱即用”的安全文件传输通道FTPS 的上手成本明显偏高。SFTP 则完全不需要额外证书。它走的是 SSH 加密协议端口、会话、认证全过程加密而且天然支持密钥认证。最关键的一点SFTP 不是独立服务它只是 SSH 大小说里的一个子系统。所以只要 SSH 服务端正常SFTP 就一定会正常不需要为文件传输单独开两三个端口。1.2 Windows 上搭 SSH/SFTP 有哪几条路Windows 上能跑 SSH 服务端的方案不少整理下来大致分三类方案优点缺点适用场景Windows 原生 OpenSSH系统自带/可选功能安装免费命令行控制方便微软官方维护配置全靠文本文件目录锁定不如第三方灵活个人使用、小团队、运维人员习惯命令行的环境Bitvise SSH Server图形界面配置支持虚拟账号、目录自动锁定、详细的权限控制免费版有限制代码不开源需要给外部用户开账号、又不想碰命令行的企业场景Cygwin / MSYS2 上的 OpenSSH更像 Linux 环境配合 shell 脚本能力更强安装包大环境管理较复杂后续更新麻烦需要在 Windows 上跑大量 UNIX 脚本的冷门情况我自己用得最多的是原生 OpenSSH。理由很现实Windows 11 和 Windows Server 2019 开始就是系统可选功能一个 PowerShell 命令就装完不引入第三方安装包安全更新跟着系统走审计也方便。但如果你要管理的是几十个外部供应商账号而且不想在 NTFS 权限里做精细的 ACL 设置那 Bitvise SSH Server 的虚拟账号功能能省掉很多事。这两条路下面会有详细的实操步骤。1.3 先想清楚你用 SFTP 要解决什么问题在动手之前建议先理清几个需求点因为它们直接决定你怎么配是内部同事用还是外部客户/供应商用外部使用通常要严格限制目录访问范围。每个用户需要独立目录还是大家共用一个共享目录要不要禁用密码登录、只允许密钥安全要求高的话一定选密钥。需要改默认 22 端口吗如果是暴露在公网环境强烈建议换一个高位端口。这些看起来都是小问题但等配置到一半再回头改会浪费不少时间。我后面写的所有步骤都是按“外部用户独立目录密码/密钥双模式”这个默认需求来展开的。2. 安装 SSH 服务端Windows 11 与 Server 2016 的三种装法2.1 Windows 11 / Windows Server 2019 一键安装原生 OpenSSHWindows 11 专业版和 Windows Server 2019/2022/2025 都自带 OpenSSH 的可选功能模块安装方式非常简单。最快的是用 PowerShell以管理员身份打开然后跑Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0装完之后直接启动服务并设置为开机自启Start-Service sshd Set-Service -Name sshd -StartupType Automatic如果你的系统里还没有 OpenSSH 客户端顺手也装一下Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0验证安装是否成功可以执行Get-Service sshd输出里Status如果是Running说明服务已经在跑了。这里我要多说一句很多人装完觉得还要装“SFTP 服务”其实不需要OpenSSH 服务端本身就自带 SFTP 子系统装好 SSH 就等于装好了 SFTP。图形化方式也可以在“设置 → 系统 → 可选功能 → 添加可选功能”里搜索“OpenSSH 服务器”点击安装即可。效果和 PowerShell 一样但 PowerShell 更适合服务器批量操作。2.2 Windows Server 2016 手动部署 OpenSSHWindows Server 2016 是比较特殊的版本——它没有把 OpenSSH 作为可选功能集成到系统组件里只能手动下载二进制包安装。很多老机房的机器还是 2016所以这个流程我单独写一遍。先去 GitHub 的 Win32-OpenSSH 官方 Release 页面下载最新版本的OpenSSH-Win64.zip下载后解压到C:\Program Files\OpenSSH目录。接着用管理员身份打开 PowerShell进入解压目录执行cd C:\Program Files\OpenSSH powershell -ExecutionPolicy Bypass -File install-sshd.ps1这个脚本会自动完成几件事把 sshd 注册成 Windows 服务、生成主机密钥host key、在防火墙里添加 22 端口入站规则。执行完脚本后启动服务Start-Service sshd Set-Service -Name sshd -StartupType Automatic有一点要注意Win32-OpenSSH 在 Server 2016 上运行需要系统打够基础补丁尤其是 .NET Framework。如果安装后服务启动失败先检查系统更新是不是最新的再检查服务是否存在于services.msc列表中。2.3 不想折腾命令行的替代方案Bitvise SSH Server如果你是 Windows 图形化操作的忠实用户或者需要同时给几十个外部账号做目录隔离、权限控制我推荐试一试 Bitvise SSH Server。这个工具做了二十多年在 Windows 上的 SSH 服务端里属于老牌产品。安装过程基本是下一步下一步装完打开控制面板就能看到主界面。它的核心优势在于账号管理可以使用 Windows 系统账号也可以创建“虚拟账号”虚拟账号不依赖 Windows 用户体系单独管理。每个账号可以单独指定 SFTP 根目录用户登录后被牢牢限制在这个目录里不会像原生 OpenSSH 那样还要手动调 NTFS 权限。支持密钥认证、双因子认证、限速、会话超时等企业级功能。如果只是需要快速上线一个 SFTP而且不打算花时间研究sshd_configBitvise 是性价比很高的选择。免费版对个人和小团队够用大并发或者商业环境需要购买授权。我后面主要以原生 OpenSSH 为主来展开但第 3 章权限相关的痛点Bitvise 用户同样值得看看。3. sshd_config 核心配置与 SFTP 用户权限3.1 sshd_config 里与 SFTP 相关的关键项逐行解读装好 OpenSSH 后配置文件一般在C:\ProgramData\ssh\sshd_config。注意不是C:\Windows\System32\OpenSSH目录下的系统默认配置放在ProgramData里。用记事本或者 VS Code 打开后不需要大改但下面几项必须重点确认# 端口默认 22公网环境建议修改为高位端口如 2222 Port 22 # 协议版本OpenSSH 7.x 以后默认就是 Protocol 2不需要手动写 Protocol 2 # 是否允许公钥认证 PubkeyAuthentication yes # 是否允许密码认证安全要求高时改成 no PasswordAuthentication yes # SFTP 子系统这一行是 SFTP 能用的核心绝不能注释掉 Subsystem sftp sftp-server.exe # 登录失败重试次数 MaxAuthTries 4 # 会话保活客户端多长时间发送一次心跳 ClientAliveInterval 300 ClientAliveCountMax 2 # 限制登录用户推荐加到配置末尾 AllowUsers sftpuser这里我要特别强调Subsystem sftp sftp-server.exe这一行。OpenSSH 的 SFTP 能力不是一个独立进程在监听端口而是由 SSH 服务端在收到 SFTP 请求时调用sftp-server.exe这个程序来处理文件操作。如果这一行被注释或者路径不对SSH 能正常连上但 SFTP 客户端会报“子系统不可用”或直接断开连接。改完配置后重启 sshd 让配置生效Restart-Service sshd3.2 创建 SFTP 专用用户并设置文件目录权限强烈建议不要用 Administrator 账号来做 SFTP 传输。管理员账号权限太大一旦被外部拿到整个系统就暴露了。正确做法是创建独立的本地用户只授予它特定目录的读写权限。在管理员 PowerShell 里执行# 创建用户密码需要符合复杂度要求 net user sftpuser 你的强密码 /add # 把用户加入 Users 组一般默认就在并把用户从 Administrators 组移除如果存在 net localgroup Administrators sftpuser /delete # 创建数据根目录 New-Item -ItemType Directory -Path D:\SFTPRoot -Force然后给用户分配 NTFS 权限。这一步是关键中的关键。在 Linux 上你只要把一个用户的家目录设置好再用 chroot 锁住即可Windows 上则要用icacls来控制访问权限# 给 sftpuser 对 D:\SFTPRoot 的完全控制权同时继承到子目录 icacls D:\SFTPRoot /grant sftpuser:(OI)(CI)M如果你想创建多个用户各自用独立的子目录操作方式是这样的New-Item -ItemType Directory -Path D:\SFTPRoot\user_a -Force icacls D:\SFTPRoot\user_a /grant user_a:(OI)(CI)M做完之后用户user_a只能在自己的目录里读写。这个思路和 Linux 的“每个用户一个 home 目录”是等效的只是底层权限模型不同。3.3 Windows 上没有 chroot如何真正把用户锁在目录里这是 Windows 上配置 SFTP 最容易踩坑的地方也是很多从 Linux 转过来的同行最困惑的点。Linux 的 OpenSSH 支持ChrootDirectory可以把 SFTP 用户直接锁在某个目录里用户看到的就是一个独立的文件系统根目录。但 Windows 版 OpenSSH 目前不支持ChrootDirectory选项在sshd_config里写了这行sshd 会直接报错或者忽略。那 Windows 靠什么来限制目录靠 NTFS 权限。默认情况下普通用户对C:\是“只读执行”权限对某些系统目录有读取权限。所以如果你只把用户加进系统而不做任何权限处理用户虽然能通过 SFTP 登录但理论上可以浏览系统里他有权读取的文件列表虽然不能写但已经不符合“隔离”的要求了。解决思路有两个第一种是上面说的给用户一个专用目录再用icacls把目录授权给用户同时从服务器上移除其他用户对该目录的访问权限。但要注意Windows 的用户目录和系统盘之间盘根错节如果希望用户“什么都看不到”光靠 NTFS 一个个目录删权限会非常痛苦而且容易把系统弄坏。第二种是使用带虚拟账号能力的第三方 SSH Server比如前面提到的 Bitvise。它可以在 SSH 层面直接给用户定义一个“虚拟根目录”用户登录后只能看到这个目录完全不需要去动系统 NTFS ACL。这也是我在生产环境给外部客户开账号时更推荐 Bitvise 的原因。如果你坚持用原生 OpenSSH 并且要求严格隔离我的建议是单独给 SFTP 数据挂一块独立分区或独立磁盘不对系统盘做调整把用户的数据目录都放在这块盘上只在这个盘上做 ACL 控制。这样既安全又不会影响系统本身的运行。4. 防火墙、端口与联调测试4.1 开放防火墙端口和排查端口监听安装脚本一般会自动创建防火墙入站规则但我在实际部署中发现Windows Server 上有时会因为组策略、云安全组等原因导致规则没有生效所以手动加一遍更稳妥。New-NetFirewallRule -Name OpenSSH-Server -DisplayName OpenSSH Server (sshd) -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22如果你的 SSH 改到了自定义端口把-LocalPort改成对应端口即可。另外云服务器通常还有一层安全组比如阿里云、腾讯云、AWS一定要在控制台的安全组规则里把 22 端口或自定义端口对目标 IP 放行。很多人本地测试没问题、远程连不上问题就出在这一层。检查端口是否真正在监听执行netstat -an | findstr :22正常输出会看到LISTENING状态的记录监听地址一般是0.0.0.0:22和[::]:22。如果只有本机回环地址127.0.0.1:22说明 sshd 配置里可能限制了ListenAddress需要检查sshd_config里是不是写了ListenAddress 127.0.0.1。4.2 用系统自带 sftp 命令完整测试一遍配置完成、端口通了之后先别急着用第三方工具Windows 11 和 Windows Server 2016 都自带了ssh和sftp客户端命令行直接在命令行验证最干净。先在服务器本机上测试ssh localhost -l sftpuser输入密码后如果能进入 shell 或 PowerShell说明 SSH 基本认证通过。接下来重点测试 SFTP 子系统sftp sftpuserlocalhost如果看到sftp提示符说明 SFTP 子系统也正常。在这个提示符下可以执行几个常用命令验证pwd # 查看当前目录 ls # 列出文件 put D:\test.txt . # 上传文件 get 文件名 # 下载文件 quit # 退出put上传成功、get下载成功说明读写权限都没问题。如果put报权限错误多半是目录 NTFS 权限没给够回到第 3 章用icacls重新授权。4.3 WinSCP / FileZilla 图形化连接验证命令行测试通过后再用图形化工具连一次确认实际使用没问题。WinSCP 和 FileZilla 都支持 SFTP 协议。WinSCP 的连接配置是这样的文件协议选“SFTP”主机名填服务器 IP端口填 22 或自定义端口用户名填sftpuser密码填用户密码。点登录后正常情况下能看到服务端的文件目录直接拖拽文件就能完成上传下载。FileZilla 类似协议选“SFTP - SSH File Transfer Protocol”主机填 IP端口填 22用户和密码照填。如果连接时报“收到 SSH 报文但无法解析”通常是端口填成了 FTP 的 21或者目标机器上根本没跑 sshd。有个经验是WinSCP 连接成功后先看主界面顶部的“协议”和“端口”有没有显示对。很多人在 WinSCP 里把“文件协议”选成了“FTP”密码再对也连不上。5. 密钥认证与安全加固5.1 生成密钥对并部署 authorized_keys密码登录简单方便但暴露在公网上的服务器密码爆破是常态。推荐的做法是改用密钥认证密码认证只在特殊情况下开。在客户端机器上Windows 10/11 自带 ssh-keygen打开 PowerShell 执行ssh-keygen -t ed25519 -C sftp-key一路回车即可生成的密钥默认在C:\Users\你的用户名\.ssh\目录下id_ed25519是私钥id_ed25519.pub是公钥。如果客户端是旧系统不支持 Ed25519可以用 RSAssh-keygen -t rsa -b 4096然后要把公钥放到服务器的对应用户目录下。在服务器上操作# 以 sftpuser 身份创建 .ssh 目录或者用管理员创建后改所有者 New-Item -ItemType Directory -Path C:\Users\sftpuser\.ssh -Force把客户端生成的id_ed25519.pub文件内容追加到C:\Users\sftpuser\.ssh\authorized_keys文件里。最简单的方法是用记事本打开公钥文件把里面一整行内容复制到 authorized_keys 里保存。这里有个大坑Windows OpenSSH 对authorized_keys文件的权限极其敏感如果权限过宽服务端会直接忽略这个文件密钥认证就会失败而且日志里几乎不会给你明确提示。修复方式是用icacls重新设置权限icacls C:\Users\sftpuser\.ssh\authorized_keys /inheritance:r /grant sftpuser:F /grant SYSTEM:F /grant Administrators:F设置完后在客户端连接试试ssh sftpuser服务器IP -i C:\Users\你的用户名\.ssh\id_ed25519如果不再要求输入密码说明密钥认证已经生效。接着在sshd_config里把密码认证关掉PasswordAuthentication no重启 sshd之后所有连接都只能用密钥安全性提升一个档次。5.2 修改 SSH 默认端口减少暴露风险把 22 端口换成其他高位端口比如 2222 或 50222可以有效减少大规模端口扫描的骚扰。修改方式很简单在C:\ProgramData\ssh\sshd_config中找到#Port 22改成Port 2222然后重启服务Restart-Service sshd记得同时进行三处配套修改防火墙规则改到 2222 端口云安全组放行 2222客户端连接时指定端口ssh -p 2222 userhost、WinSCP 的端口栏改成 2222。改端口不能解决被暴力破解的问题但能把 90% 无聊的扫描攻击挡在外面。5.3 服务自启、日志审计与日常检查确保 sshd 开机自启Set-Service -Name sshd -StartupType AutomaticOpenSSH 在 Windows 上的日志记录方式和 Linux 不太一样它不走/var/log/secure而是写入 Windows 事件日志。查看路径是事件查看器 → 应用程序和服务日志 → OpenSSH → Operational。所有登录成功、失败、认证错误的记录都在这里排错时第一反应应该是看这个日志而不是靠猜。日常检查服务状态Get-Service sshd如果服务掉了先看事件日志里最近的错误信息再决定是检查端口占用还是检查配置文件。我的习惯是改配置之前先备份一份sshd_config改坏了能立即回滚。6. 常见问题排查与坑位记录6.1 连接类问题卡在“请稍后”、连接被拒绝、超时这类问题出现频率最高我整理成一张速查表方便你按图索骥现象可能原因排查步骤SSH 连接一直转圈“请稍后”客户端走了代理或 SSH 服务端端口不通关闭系统代理telnet IP 端口测试端口连通性连接被拒绝sshd 服务没启动、端口被占用Get-Service sshdnetstat -an | findstr :22连接超时云安全组没放行、本地防火墙拦截检查安全组入站规则Test-NetConnection IP -Port 22能连上但登录失败用户不在允许列表、密码错误、用户被禁用看 OpenSSH/Operational 日志检查AllowUsers确认密码未过期密钥登录不生效authorized_keys 权限过宽、公钥内容写错用icacls修复权限检查公钥是否整行粘贴且无多余空格其中“卡在请稍后”这个现象很典型尤其是在 Windows 11 上用某些终端工具连接时。排查思路是先确认网络通不通再确认端口有没有防火墙拦截然后关掉终端工具的代理设置。很多时候不是服务器问题是客户端网络环境有代理在干扰。6.2 文件传输类问题能登录但上传失败、速度慢、目录看不到SFTP 登录成功但put文件时报Permission denied这个问题几乎全是 NTFS 权限问题。回到第 3 章用icacls把你需要开放的目录授权给对应用户注意要带(OI)(CI)参数这样权限才能继承到子文件和子目录。还有一类问题在 Windows Server 上比较隐蔽用户在共享目录上传文件后其他用户无法覆盖或读取这是因为 NTFS 默认的 ACL 继承规则在作怪。解决方式是打开目录属性 → 安全选项卡确认所有需要访问的用户/用户组都有“修改”权限或者直接在icacls里把 Everyone 的写权限去掉、只留指定用户。另外如果文件上传速度很慢检查客户端和服务端之间的 MTU、以及 SSH 的加密算法是否过于消耗 CPU。老旧的 Windows Server 2016 如果用 RSA 4096 密钥交换CPU 占用会明显偏高建议客户端算法优先选curve25519-sha256、chacha20-poly1305openssh.com这类现代算法。6.3 VS Code Remote-SSH 连上 Windows 后报“扩展被禁用”怎么办用 VS Code 的 Remote-SSH 扩展连接 Windows 服务器时你可能会遇到这样的提示此扩展在此工作区中被禁用因为其被定义为在远程扩展主机中运行。这个不是 SFTP 服务本身的故障而是 VS Code 扩展的机制限制——很多扩展在声明时只标注支持 Linux/macOS 远程主机不支持 Windows 远程。想继续在 Windows 上做远程开发可以考虑两个方向本机直接映射网络驱动器或者用 SFTP 同步插件如 SFTP 扩展把文件同步到本地编辑而不是用 Remote-SSHWindows 服务器上启用 OpenSSH 后远程登录默认进入的是 CMD 或 PowerShell本身就是一个可用的远程终端不一定要用 VS Code。这个场景提醒我们SSH 登录成功和 SFTP 文件传输成功是两件事配置完成后必须分别验证不要因为命令行能进就觉得一切正常。最后再分享一个小习惯每次新装完一台 Windows 服务器的 OpenSSH我都会在本机跑一遍sftp localhost而不是只测ssh localhost。原因很简单SSH 登录成功只能说明服务端和认证没问题SFTP 子系统是否启动、权限是否正确只有真正进入sftp提示符执行一次put和get才能确认。这一条验证步骤不仅能帮你快速定位问题也能避免后期给客户开通账号时才发现传不了文件的尴尬。另外配置文件动过之后我习惯先执行net stop sshd再net start sshd如果服务启动失败错误信息会直接弹出来比Restart-Service吞掉错误提示要好排查得多。Windows 上跑 SFTP本身不是什么难点但它和 Linux 的习惯差异确实不少把权限模型想清楚后面就顺了。