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
相关推荐
CCPC不拿奖不改名1 小时前
大模型推理架构与开源生态知识整理
数据库·windows·python·架构·langchain·开源·github
王维同学4 小时前
[自学][Windows C++]RunOnceEx 注册表分组键的安全遍历
c++·windows·安全·开源
imatt8 小时前
Qt Creator 在Windows下编译信息乱码
windows·qt
就不掉头发8 小时前
计算机的虚拟内存
linux·服务器·windows
我变秃了也没变强9 小时前
oepnssh版本升级
ssh
春风霓裳11 小时前
window设置永不更新
windows
luyun02020213 小时前
专防未成年,吾爱出品
网络·windows·figma
love530love1 天前
【笔记】AutoClaw NSIS 安装器卡死、进程杀不掉、目录删不了?我是这么解决的
人工智能·windows·笔记·agent
大模型码小白1 天前
JAVA 集合框架进阶:List 与 Set 的深度解析与实战
java·开发语言·人工智能·windows·语言模型·list·ai编程
XUHUOJUN1 天前
AKS 不是安装在 Windows Server 上,而是运行在 Windows Server 之上的 Azure 平台能力
windows·架构·k8s·azure local·azure stack