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