Windows Server 2019 离线安装 OpenSSH 并仅启用 SFTP

适用场景:

  • Windows Server 2019 无外网环境
  • 替代 freeSSHd,解决 Linux SFTP 中文文件名乱码
  • 仅允许 SFTP 传输,禁止 SSH 交互登录

一、总体说明

  • OpenSSH 不管理账号 ,直接使用 Windows 本地用户 / 域用户
  • SFTP 文件名 原生 UTF-8,Linux / FileZilla 均不会乱码
  • 通过 ForceCommand internal-sftp 实现 SFTP-only

二、离线安装 OpenSSH(官方推荐方式)

1. 准备安装包(有网机器)

下载微软官方 OpenSSH:

拷贝到目标服务器,例如:

text 复制代码
C:\install\OpenSSH-Win64.zip

2. 解压到固定目录

text 复制代码
C:\Program Files\OpenSSH

目录中应包含:

text 复制代码
sshd.exe
ssh.exe
sftp-server.exe
install-sshd.ps1

3. 安装 OpenSSH 服务

管理员 PowerShell 执行:

powershell 复制代码
cd "C:\Program Files\OpenSSH"
powershell -ExecutionPolicy Bypass -File install-sshd.ps1

成功后会生成两个服务:

  • OpenSSH SSH Server (sshd)
  • OpenSSH Authentication Agent (ssh-agent)

4. 启动服务并设置开机自启

powershell 复制代码
Start-Service sshd
Set-Service sshd -StartupType Automatic
Start-Service ssh-agent

验证:

powershell 复制代码
Get-Service sshd

5. 放行防火墙端口(22)

5.1 入站规则(必需)

允许外部客户端连接到服务器:

powershell 复制代码
New-NetFirewallRule \
  -Name OpenSSH-Server-In-TCP \
  -DisplayName "OpenSSH Server (sshd)" \
  -Enabled True \
  -Direction Inbound \
  -Protocol TCP \
  -Action Allow \
  -LocalPort 22
5.2 出站规则(可选,严格安全环境推荐)

允许服务器响应客户端连接(通常 Windows 防火墙默认允许出站,但明确配置更安全):

powershell 复制代码
New-NetFirewallRule \
  -Name OpenSSH-Server-Out-TCP \
  -DisplayName "OpenSSH Server (sshd) Outbound" \
  -Enabled True \
  -Direction Outbound \
  -Protocol TCP \
  -Action Allow \
  -LocalPort 22

说明:

  • 入站规则:必需,允许客户端连接到服务器
  • 出站规则:可选,在严格安全策略环境中推荐配置
  • Windows 防火墙默认允许出站连接,但明确配置可提高可审计性

三、创建 SFTP 专用账号与目录

1. 创建本地用户(示例)

powershell 复制代码
net user sftpuser StrongP@ssw0rd! /add

说明:

  • 用户名、密码可按公司规范调整
  • 也可使用域账号:DOMAIN\\username

2. 创建 SFTP 目录结构

示例目录:

text 复制代码
D:\sftpdata\sftpuser
powershell 复制代码
mkdir D:\sftpdata\sftpuser

3. 设置 NTFS 权限(非常关键)

3.1 Chroot 根目录权限(只允许管理员)
powershell 复制代码
icacls D:\sftpdata /inheritance:r
icacls D:\sftpdata /grant Administrators:(OI)(CI)F
icacls D:\sftpdata /grant SYSTEM:(OI)(CI)F
3.2 用户子目录权限
powershell 复制代码
icacls D:\sftpdata\sftpuser /inheritance:r
icacls D:\sftpdata\sftpuser /grant sftpuser:(OI)(CI)F

⚠ 注意:

  • Chroot 根目录不能给用户写权限
  • 否则 SFTP 会直接断开连接

四、配置仅允许 SFTP(禁用 SSH 登录)

1. 编辑 sshd_config

文件路径:

text 复制代码
C:\ProgramData\ssh\sshd_config

2. 确认 SFTP 子系统

conf 复制代码
Subsystem sftp sftp-server.exe

3. 添加 SFTP-only 配置(文件末尾)

conf 复制代码
Match User sftpuser
    ChrootDirectory D:\sftpdata
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

配置说明:

配置项 作用
ForceCommand internal-sftp 禁止 SSH Shell
ChrootDirectory 限制用户根目录
AllowTcpForwarding no 禁用端口转发
X11Forwarding no 禁用图形转发

4. 重启 OpenSSH 服务

powershell 复制代码
Restart-Service sshd

五、验证测试

1. 测试 SSH(应被禁止)

bash 复制代码
ssh sftpuser@windows_ip

期望结果:

text 复制代码
This service allows sftp connections only.

2. 测试 SFTP(应成功)

bash 复制代码
sftp sftpuser@windows_ip
put 测试文件.txt

验证点:

  • 中文文件名正常
  • 只能访问指定目录
  • 无法执行任何命令

六、常见问题排查

1. SFTP 连接即断开

  • 检查 Chroot 根目录是否给了用户写权限
  • 确认使用的是 internal-sftp

2. 修改配置未生效

  • 忘记重启 sshd 服务

3. 中文仍乱码

  • 确认已弃用 freeSSHd
  • 使用的是官方 OpenSSH

七、最终结论

  • 账号 / 密码 = Windows 用户体系
  • OpenSSH 原生支持 UTF-8
  • SFTP-only 是企业级标准方案
  • 适合生产、内网、审计环境

可扩展:

  • 多用户批量配置
  • 仅密钥登录、禁用密码
  • 操作日志与审计
  • freeSSHd 平滑迁移

很好,这两个点(限制 IP + 修改端口 )确实是生产环境必配项 👍

我刚才已经尝试直接把内容补进你右侧那份 Markdown 文档里 ,但由于编辑器在匹配标题时出现了格式冲突,本次更新没有成功写入 Canvas(我没有再强行重试,避免破坏原文档结构)。

下面我把你需要新增的完整 Markdown 内容 整理好,你可以直接整体复制,按推荐位置插入到文档中即可(我也会告诉你插到哪)。


📌 建议插入位置

👉 放在「仅允许 SFTP(禁用 SSH 登录)」之后、原「常见问题排查」之前


✅ 新增章节:IP 访问限制与端口修改(Markdown)

markdown 复制代码
## 六、IP 访问限制与端口修改(安全加固)

### 1. 修改 OpenSSH 服务端口

#### 1.1 修改 sshd_config

编辑文件:

```text
C:\ProgramData\ssh\sshd_config

找到或新增端口配置(示例将端口改为 60022):

conf 复制代码
Port 60022

说明:

  • 可配置多个 Port,但生产环境建议只保留一个
  • 修改后需重启 sshd 服务

1.2 放行新端口防火墙规则

入站规则(必需):

powershell 复制代码
New-NetFirewallRule `
  -Name OpenSSH-Server-In-TCP-60022 `
  -DisplayName "OpenSSH Server (sshd) 60022" `
  -Enabled True `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -Action Allow

出站规则(可选,严格安全环境推荐):

powershell 复制代码
New-NetFirewallRule `
  -Name OpenSSH-Server-Out-TCP-60022 `
  -DisplayName "OpenSSH Server (sshd) 60022 Outbound" `
  -Enabled True `
  -Direction Outbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -Action Allow

如需关闭默认 22 端口:

powershell 复制代码
# 关闭入站规则
Get-NetFirewallRule -DisplayName "OpenSSH Server (sshd)" | Disable-NetFirewallRule

# 关闭出站规则(如果已配置)
Get-NetFirewallRule -DisplayName "OpenSSH Server (sshd) Outbound" | Disable-NetFirewallRule

1.3 重启服务
powershell 复制代码
Restart-Service sshd

2. 限制允许访问的客户端 IP(推荐方式)

2.1 使用 Windows 防火墙限制 IP(最稳妥)

示例:只允许 192.168.10.100 访问 SFTP 端口 60022:

入站规则(允许指定 IP):

powershell 复制代码
New-NetFirewallRule `
  -Name OpenSSH-Allow-192.168.10.100 `
  -DisplayName "OpenSSH Allow 192.168.10.100" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress 192.168.10.100 `
  -Action Allow

出站规则(响应指定 IP,可选):

powershell 复制代码
New-NetFirewallRule `
  -Name OpenSSH-Allow-192.168.10.100-Out `
  -DisplayName "OpenSSH Allow 192.168.10.100 Outbound" `
  -Direction Outbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress 192.168.10.100 `
  -Action Allow

阻断其他来源(入站):

powershell 复制代码
New-NetFirewallRule `
  -Name OpenSSH-Deny-Other-IP `
  -DisplayName "OpenSSH Deny Other IP" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress Any `
  -Action Block

⚠ 注意

  • 防火墙规则优先级:允许 > 阻断
  • 入站规则:控制谁可以连接到服务器
  • 出站规则:控制服务器可以响应哪些客户端(可选,但推荐在严格环境中配置)
  • 推荐用于生产 / 内网隔离 / 审计场景

2.2 限制 IP 后无法连接的故障排查

问题现象:

  • 通用规则(无 RemoteAddress)可以连接
  • 限制 IP 的规则(有 RemoteAddress)无法连接

原因分析:

  1. 存在多个规则冲突(通用规则和限制规则同时存在)
  2. 规则优先级问题
  3. 之前的通用规则未删除或禁用

解决方法:

步骤 1:查看当前所有相关规则

powershell 复制代码
Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*OpenSSH*60022*" -or $_.LocalPort -eq 60022 } | Format-Table DisplayName, Direction, Action, Enabled, RemoteAddress

步骤 2:删除或禁用之前的通用规则

如果之前创建了通用规则(无 RemoteAddress),需要先删除或禁用:

powershell 复制代码
# 方法 1:禁用通用规则(推荐,保留规则记录)
Get-NetFirewallRule -DisplayName "Allow OpenSSH Port 60022" | Disable-NetFirewallRule

# 方法 2:删除通用规则
Remove-NetFirewallRule -DisplayName "Allow OpenSSH Port 60022" -ErrorAction SilentlyContinue

步骤 3:确保限制 IP 的规则已正确创建

powershell 复制代码
# 创建限制 IP 的规则(确保 Enabled=True)
New-NetFirewallRule `
  -Name OpenSSH-Allow-192.168.34.18 `
  -DisplayName "OpenSSH Allow 192.168.34.18" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress 192.168.34.18 `
  -Action Allow `
  -Enabled True

步骤 4:验证规则优先级

Windows 防火墙规则优先级(从高到低):

  1. 明确允许规则(Allow + 特定 RemoteAddress)
  2. 明确阻止规则(Block + 特定 RemoteAddress)
  3. 通用允许规则(Allow + Any)
  4. 通用阻止规则(Block + Any)

步骤 5:测试连接

bash 复制代码
# 从允许的 IP 测试
telnet 192.168.31.107 60022

# 或使用 SFTP
sftp -P 60022 test@192.168.31.107

完整配置示例(推荐顺序):

powershell 复制代码
# 1. 先删除或禁用所有旧规则
Get-NetFirewallRule | Where-Object { $_.DisplayName -like "*OpenSSH*60022*" } | Remove-NetFirewallRule -ErrorAction SilentlyContinue

# 2. 创建限制 IP 的允许规则
New-NetFirewallRule `
  -Name OpenSSH-Allow-192.168.34.18 `
  -DisplayName "OpenSSH Allow 192.168.34.18" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress 192.168.34.18 `
  -Action Allow `
  -Enabled True

# 3. 创建阻止其他 IP 的规则(可选,更严格)
New-NetFirewallRule `
  -Name OpenSSH-Deny-Other-IP `
  -DisplayName "OpenSSH Deny Other IP" `
  -Direction Inbound `
  -Protocol TCP `
  -LocalPort 60022 `
  -RemoteAddress Any `
  -Action Block `
  -Enabled True

3. 通过 sshd_config 限制 IP(可选补充)

sshd_config 中添加:

conf 复制代码
AllowUsers sftpuser@192.168.10.100

限制整个网段示例:

conf 复制代码
AllowUsers sftpuser@192.168.10.*

修改后重启服务:

powershell 复制代码
Restart-Service sshd

建议:

  • IP 控制优先用防火墙
  • sshd_config 作为逻辑层补充

八、验证测试(端口 & IP)

1. 指定端口连接

bash 复制代码
sftp -P 60022 sftpuser@windows_ip

2. 非允许 IP 测试

  • 连接应被拒绝或超时


    ✅ 给你的最终建议(运维视角)

    生产推荐组合:

    • ✔ 修改默认 22 → 自定义端口
    • ✔ Windows 防火墙限制来源 IP
    • ForceCommand internal-sftp
    • ✔ Chroot + 最小权限目录

    👉 这套配置已经是企业级 SFTP 基线


    如果你愿意,下一步我还能帮你把整份文档再升级一版,例如:

    • 🔐 禁用密码,仅允许密钥登录
    • 📜 SFTP 上传 / 下载审计日志
    • 🧩 多用户统一模板(复制即用)
    • 🔄 freeSSHd → OpenSSH 迁移 checklist
相关推荐
悟能不能悟2 小时前
java list.addAll介绍
java·windows·list
问道飞鱼2 小时前
【Rust编程知识】在 Windows 下搭建完整的 Rust 开发环境
开发语言·windows·后端·rust·开发环境
weixin_516023072 小时前
bitlocker加密的关闭
windows
0.0雨3 小时前
设置集群的SSH免密登陆
linux·服务器·ssh
回吐泡泡oO3 小时前
Windows系统服务器蓝屏解决方案
windows
派大鑫wink3 小时前
【Day13】集合框架(一):List 接口(ArrayList vs LinkedList)实战
java·开发语言·windows
love530love4 小时前
让 ComfyUI 官方 CLI 在 Windows CMD 里也能 Tab 补全 —— 实测与避坑记录
人工智能·windows·python·clink·comfy-cli·命令补全·clickcompletion
Rabi'4 小时前
Windows系统 Qt 整合 OpenCV4.12.0
开发语言·windows·qt·opencv
友莘居士4 小时前
Windows下Node.js 执行Web3.js 的智能合约环境搭建
windows·node.js·web3