Windows SSH远程登录
Categories:
在 Windows 上开启 SSH 远程访问通常需要使用到 Windows 的 OpenSSH 功能。以下是详细的步骤说明:
检查并安装 OpenSSH
检查 OpenSSH 是否已安装:
- 打开“设置” > “应用” > “应用和功能” > “管理可选功能”。
- 在已经安装的列表中查找“OpenSSH 服务器”。如果存在,则表示它已经被安装。
安装 OpenSSH:
- 如果没有找到 OpenSSH 服务器,可以在“管理可选功能”页面点击“添加功能”,然后在列表中找到“OpenSSH 服务器”,点击“安装”。
启动并设置 OpenSSH 服务
启动 OpenSSH 服务:
- 安装完成后,打开命令提示符(以管理员身份运行)。
- 输入
net start sshd
来启动 OpenSSH 服务。如果想要每次开机时自动启动该服务,可以输入sc config sshd start= auto
。
配置防火墙:
- 确保 Windows 防火墙允许 SSH 连接。可以通过“控制面板” > “系统和安全” > “Windows Defender 防火墙” > “高级设置”,然后新建入站规则,允许 TCP 端口 22 的连接。
获取 IP 地址并进行连接测试
获取 IP 地址:
- 要从另一台机器连接到这台开启了 SSH 服务的 Windows 电脑,你需要知道它的 IP 地址。可以在命令提示符下使用
ipconfig
命令来查看本机的 IP 地址。
- 要从另一台机器连接到这台开启了 SSH 服务的 Windows 电脑,你需要知道它的 IP 地址。可以在命令提示符下使用
连接测试:
- 在另一台电脑或移动设备上使用 SSH 客户端(例如:PuTTY、Termius 等)尝试连接到你的 Windows PC,使用格式
ssh username@your_ip_address
。其中username
是你要登录的 Windows 账户名,your_ip_address
是你之前查到的 IP 地址。
- 在另一台电脑或移动设备上使用 SSH 客户端(例如:PuTTY、Termius 等)尝试连接到你的 Windows PC,使用格式
修改配置
注意避免使用密码登录,这是绝对的雷区。务必使用公钥进行登录,我们需要修改设置,禁用密码登录,允许公钥登录。
该配置文件不便修改,需要特殊权限才能修改,同时还需要保证其目录和文件的权限为特定值,这里推荐使用脚本进行修改。
# 检查管理员权限
$elevated = [bool]([System.Security.Principal.WindowsPrincipal]::new(
[System.Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator))
if (-not $elevated) {
Write-Error "请以管理员身份运行此脚本"
exit 1
}
# 1. 检查并安装 OpenSSH 服务器
Write-Host "正在检查 OpenSSH 服务器安装状态..."
$capability = Get-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
if ($capability.State -ne 'Installed') {
Write-Host "正在安装 OpenSSH 服务器..."
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 | Out-Null
}
# 2. 启动并设置开机自启 SSH 服务
Write-Host "正在配置 SSH 服务..."
$service = Get-Service sshd -ErrorAction SilentlyContinue
if (-not $service) {
Write-Error "OpenSSH 服务安装失败"
exit 1
}
if ($service.Status -ne 'Running') {
Start-Service sshd
}
Set-Service sshd -StartupType Automatic
# 3. 修改配置文件
$configPath = "C:\ProgramData\ssh\sshd_config"
if (Test-Path $configPath) {
Write-Host "正在备份原始配置文件..."
Copy-Item $configPath "$configPath.bak" -Force
} else {
Write-Error "找不到配置文件: $configPath"
exit 1
}
Write-Host "正在修改 SSH 配置..."
$config = Get-Content -Path $configPath -Raw
# 启用公钥认证并禁用密码登录
$config = $config -replace '^#?PubkeyAuthentication .*$','PubkeyAuthentication yes' `
-replace '^#?PasswordAuthentication .*$','PasswordAuthentication no'
# 确保包含必要配置
if ($config -notmatch 'PubkeyAuthentication') {
$config += "`nPubkeyAuthentication yes"
}
if ($config -notmatch 'PasswordAuthentication') {
$config += "`nPasswordAuthentication no"
}
# 写回配置文件
$config | Set-Content -Path $configPath -Encoding UTF8
authorized_keys 文件权限确认
# normal user
$authKeys = "$env:USERPROFILE\.ssh\authorized_keys"
icacls $authKeys /inheritance:r /grant "$($env:USERNAME):F" /grant "SYSTEM:F"
icacls "$env:USERPROFILE\.ssh" /inheritance:r /grant "$($env:USERNAME):F" /grant "SYSTEM:F"
# administrator
$adminAuth = "C:\ProgramData\ssh\administrators_authorized_keys"
icacls $adminAuth /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
设置防火墙规则
# 允许 SSH 端口
New-NetFirewallRule -DisplayName "OpenSSH Server (sshd)" -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
增加公钥
普通用户
# normal user
$userProfile = $env:USERPROFILE
$sshDir = Join-Path $userProfile ".ssh"
$authorizedKeysPath = Join-Path $sshDir "authorized_keys"
$PublicKeyPath = "D:\public_keys\id_rsa.pub"
# 创建 .ssh 目录
if (-not (Test-Path $sshDir)) {
New-Item -ItemType Directory -Path $sshDir | Out-Null
}
# 设置 .ssh 目录权限
$currentUser = "$env:USERDOMAIN\$env:USERNAME"
$acl = Get-Acl $sshDir
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$currentUser, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$acl.AddAccessRule($rule)
Set-Acl $sshDir $acl
# 添加公钥
if (Test-Path $PublicKeyPath) {
$pubKey = Get-Content -Path $PublicKeyPath -Raw
if ($pubKey) {
# 确保公钥末尾有换行符
if (-not $pubKey.EndsWith("`n")) {
$pubKey += "`n"
}
# 追加公钥
Add-Content -Path $authorizedKeysPath -Value $pubKey -Encoding UTF8
# 设置文件权限
$acl = Get-Acl $authorizedKeysPath
$acl.SetSecurityDescriptorRule(
(New-Object System.Security.AccessControl.FileSystemAccessRule(
$currentUser, "FullControl", "None", "None", "Allow"
))
)
Set-Acl $authorizedKeysPath $acl
}
} else {
Write-Error "公钥文件不存在: $PublicKeyPath"
exit 1
}
# 重启 SSH 服务
Write-Host "正在重启 SSH 服务..."
Restart-Service sshd
管理员用户
# administrator
$adminSshDir = "C:\ProgramData\ssh"
$adminAuthKeysPath = Join-Path $adminSshDir "administrators_authorized_keys"
$adminPublicKeyPath = "D:\public_keys\id_rsa.pub"
# 创建管理员 SSH 目录
if (-not (Test-Path $adminSshDir)) {
New-Item -ItemType Directory -Path $adminSshDir | Out-Null
}
# 设置管理员 SSH 目录权限
$adminAcl = Get-Acl $adminSshDir
$adminRule = New-Object System.Security.AccessControl.FileSystemAccessRule(
"Administrators", "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow"
)
$adminAcl.AddAccessRule($adminRule)
Set-Acl $adminSshDir $adminAcl
# 添加管理员公钥
if (Test-Path $adminPublicKeyPath) {
$adminPubKey = Get-Content -Path $adminPublicKeyPath -Raw
if ($adminPubKey) {
# 确保公钥末尾有换行符
if (-not $adminPubKey.EndsWith("`n")) {
$adminPubKey += "`n"
}
# 追加公钥
Add-Content -Path $adminAuthKeysPath -Value $adminPubKey -Encoding UTF8
# 设置文件权限
$adminAcl = Get-Acl $adminAuthKeysPath
$adminAcl.SetSecurityDescriptorRule(
(New-Object System.Security.AccessControl.FileSystemAccessRule(
"Administrators", "FullControl", "None", "None", "Allow"
))
)
Set-Acl $adminAuthKeysPath $adminAcl
}
} else {
Write-Error "管理员公钥文件不存在: $adminPublicKeyPath"
exit 1
}
# 重启 SSH 服务
Write-Host "正在重启 SSH 服务..."
Restart-Service sshd