# 如何在 Windows 正確的安裝與設定 OpenSSH Server 服務

我這幾年有替幾位客戶實現 Windows 平台的自動化作業，我認為 Windows 在**遠端檔案傳輸**方面，一直都沒有內建非常理想的解決方案。內建的方案不外乎是開一堆 Ports 且預設傳輸沒加密的 FTP 服務、不太安全的 [WinRM](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/how-to-enable-windows-remote-shell?WT.mc_id=DT-MVP-4015686) (預設沒加密)、或是被大部分企業禁用的 SMB 協議。雖然加裝 TLS/SSL 憑證可以解決安全連線的問題，但是憑證的管理與配送，並不是所有企業都能做好，甚至門檻頗高。我認為在 Windows 平台最安全、最有效率的解決方案，還是提供 `sshd` 服務 (OpenSSH Server)，搭配 SFTP 就能進行安全的檔案傳輸，這篇文章我就來分享如何在 Windows 正確安裝 OpenSSH Server 服務的所有步驟。

> 關於 SFTP 如何安全地設定，請參閱 [如何在 Windows 架設高安全性的 SFTP (SSH File Transfer Protocol) 伺服器](/post/2021/12/12/Enhanced-Security-for-SFTP-SSH-File-Transfer-Protocol-on-Windows) 文章說明。

### 安裝 Windows 10 / Windows Server 2019+ 內建的 OpenSSH 工具

微軟官網有一份 [Install OpenSSH](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?WT.mc_id=DT-MVP-4015686) 文件，完整描述如何在 Windows 10 / Windows Server 2019 / Windows Server 2022 安裝內建的 OpenSSH 用戶端與伺服器端的軟體，但是 Windows 內建的 OpenSSH 通常不是最新版本，容易存在一些 Bugs 與缺少一些好用設定。

以下是透過 PowerShell 快速安裝的方法：

1.  先確認目前的作業系統有包含 OpenSSH 相關功能
    
    ```powershell
    Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
    ```
    
    看到以下內容就代表你目前的 Windows 可以直接用 PowerShell 安裝 OpenSSH 相關功能：
    
    ```
    Name  : OpenSSH.Client~~~~0.0.1.0
    State : NotPresent
    
    Name  : OpenSSH.Server~~~~0.0.1.0
    State : NotPresent
    ```
    
2.  安裝 OpenSSH Client 用戶端工具
    
    ```powershell
    Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
    ```
    
3.  安裝 OpenSSH Server 服務
    
    ```powershell
    Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
    ```
    
4.  啟動 OpenSSH Server 服務
    
    ```powershell
    # 啟動 sshd 服務
    Start-Service sshd
    
    # 設定 sshd 服務自動啟動
    Set-Service -Name sshd -StartupType 'Automatic'
    
    # 確認設定防火牆規則 (通常安裝後會自動設定完成，此步驟只是再確認一次)
    if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) {
        Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..."
        New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
    } else {
        Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists."
    }
    ```
    
5.  變更 `DefaultShell` 預設殼層設定
    
    Windows 內建的 OpenSSH Server 預設在使用者遠端登入的時候是使用 Command Prompt (`cmd.exe`) 作為預設殼層 (Default Shell)，你可以透過以下 PowerShell 命令修改 Registry (機碼) 設定，將預設殼層修改為 Windows PowerShell！
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
    ```
    
    > 注意: 預設殼層不影響你的 `sftp` 檔案傳輸。
    
    如果你要設定 PowerShell Core 為預設殼層的話，就需要先安裝 [PowerShell-7.2.0-win-x64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.2.0/PowerShell-7.2.0-win-x64.msi) 或 [PowerShell-7.2.0-win-x86.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.2.0/PowerShell-7.2.0-win-x86.msi)，然後執行以下 PowerShell 命令即可：
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "c:/progra~1/powershell/7/pwsh.exe" -PropertyType String -Force
    ```
    
    如果你想設定 Cygwin 的 `bash` 當成預設殼層的話，可以直接使用 Git for Windows 內建的 `bash` 版本，以下是設定方法：
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "$env:ProgramFiles\Git\bin\bash.exe" -PropertyType String -Force
    ```
    

關於完整的 OpenSSH Server 設定說明，可參考 [OpenSSH Server Configuration for Windows 10 1809 and Windows Server 2019](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration?WT.mc_id=DT-MVP-4015686) 文件。

### 安裝最新版的 Win32 OpenSSH 工具

目前 [Windows 版的 OpenSSH](https://github.com/PowerShell/Win32-OpenSSH) 是由微軟官方維護的版本，使用上比較有保障，而且支援 Windows 7 以上的任何版本。不過當你連到 GitHub 的 [Releases](https://github.com/PowerShell/Win32-OpenSSH/releases/latest) 頁面時，看到的版本號都是永遠的 Beta 版，而且所有的版本都是 Beta 版，但這些版本都是微軟完整測試過才會釋出，因此不用特別擔心穩定性的問題。

以下就是完整的安裝步驟：

1.  下載 [OpenSSH-Win64.zip](https://github.com/PowerShell/Win32-OpenSSH/releases/latest) 最新版回來
    
    ```bash
    Invoke-WebRequest -Uri https://github.com/PowerShell/Win32-OpenSSH/releases/download/V8.6.0.0p1-Beta/OpenSSH-Win64.zip -OutFile OpenSSH-Win64.zip
    ```
    
2.  請以系統管理人員身份執行 PowerShell 並將檔案複製到 `C:\Program Files\OpenSSH` 目錄下
    
    ```powershell
    # 先解壓縮到暫存資料夾
    Expand-Archive -LiteralPath "$PWD\OpenSSH-Win64.zip" -DestinationPath "$env:TEMP\OpenSSH"
    
    # 將 OpenSSH-Win64 目錄下所有檔案複製到 C:\Program Files\OpenSSH
    mkdir "$env:ProgramFiles\OpenSSH"
    Copy-Item -Path "$env:TEMP\OpenSSH\OpenSSH-Win64\*" -Destination "$env:ProgramFiles\OpenSSH" -Recurse
    ```
    
    > 這個過程必須確保只有 `SYSTEM` 系統帳戶與 `Administrator` 群組擁有 Write (寫入) 權限，其他 `Authenticated users` 都只能有「讀取與執行」(Read and Execute) 權限而已。
    
3.  移除 `SshdBroker` 服務 (Windows 10 only)
    
    如果你使用 Windows 10 而且先前安裝過內建的 OpenSSH Server 功能，如果你跟我一樣從舊版 Windows 10 一直升級到最新版的話，Windows 10 在某個**建置版本**之後就移除了 `SshdBroker` 服務，這個變更會導致無法順利安裝 OpenSSH Server (`sshd`) 服務。解決方法是透過 [PowerShell Core](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?WT.mc_id=DT-MVP-4015686) 的 `Remove-Service` 命令 (cmdlet) 將 `SshdBroker` 服務移除即可：
    
    ```powershell
    Remove-Service -Name SshdBroker -Verbose
    ```
    
    > 注意: Windows PowerShell 不支援 `Remove-Service` cmdlet
    
4.  執行安裝程序
    
    使用與前一個步驟相同的 PowerShell 工作階段(以系統管理人員身份執行)，執行以下命令：
    
    ```powershell
    cd "$env:ProgramFiles\OpenSSH"
    powershell.exe -ExecutionPolicy Bypass -File install-sshd.ps1
    ```
    
5.  啟動 OpenSSH Server 服務
    
    ```powershell
    # 啟動 sshd 服務
    Start-Service sshd
    
    # 設定 sshd 服務自動啟動
    Set-Service -Name sshd -StartupType 'Automatic'
    
    # 設定新的 OpenSSH Server 防火牆規則
    New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
    ```
    
    > 如果你之前有裝過 Windows 內建的 OpenSSH Server 功能，預設會建立一個名為 `OpenSSH-Server-In-TCP` 的內建防火牆規則，但是這條規則有綁定一個應用程式路徑，所以該條規則對 `"C:\Program Files\OpenSSH\sshd.exe"` 無效，因此必須設定新的 `sshd` 防火牆規則才行！
    
6.  變更 `DefaultShell` 預設殼層設定
    
    Windows 內建的 OpenSSH Server 預設在使用者遠端登入的時候是使用 Command Prompt (`cmd.exe`) 作為預設殼層 (Default Shell)，你可以透過以下 PowerShell 命令修改 Registry (機碼) 設定，將預設殼層修改為 Windows PowerShell！
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -PropertyType String -Force
    ```
    
    > 注意: 預設殼層不影響你的 `sftp` 檔案傳輸。
    
    如果你要設定 PowerShell Core 為預設殼層的話，就需要先安裝 [PowerShell-7.2.0-win-x64.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.2.0/PowerShell-7.2.0-win-x64.msi) 或 [PowerShell-7.2.0-win-x86.msi](https://github.com/PowerShell/PowerShell/releases/download/v7.2.0/PowerShell-7.2.0-win-x86.msi)，然後執行以下 PowerShell 命令即可：
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "c:/progra~1/powershell/7/pwsh.exe" -PropertyType String -Force
    ```
    
    如果你想設定 Cygwin 的 `bash` 當成預設殼層的話，可以直接使用 Git for Windows 內建的 `bash` 版本，以下是設定方法：
    
    ```powershell
    New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "$env:ProgramFiles\Git\bin\bash.exe" -PropertyType String -Force
    ```
    

> 如果未來要移除 Win32 OpenSSH 可以參考[這篇文章](https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH#uninstall-win32-openssh)。

### 相關連結

-   [Win32-OpenSSH](https://github.com/PowerShell/Win32-OpenSSH)
    -   [Wikis](https://github.com/PowerShell/Win32-OpenSSH/wiki)
    -   [Install Win32 OpenSSH](https://github.com/PowerShell/Win32-OpenSSH/wiki/Install-Win32-OpenSSH)
    -   [DefaultShell](https://github.com/PowerShell/Win32-OpenSSH/wiki/DefaultShell)
    -   [Installing and Enabling OpenSSH on Windows](https://docs.ssw.splashtop.com/docs/installing-and-enabling-openssh-on-windows)
-   OpenSSH
    -   [OpenSSH in Windows](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_overview?WT.mc_id=DT-MVP-4015686)
    -   [Install OpenSSH](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_install_firstuse?WT.mc_id=DT-MVP-4015686)
    -   [OpenSSH Server Configuration for Windows 10 1809 and Windows Server 2019](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_server_configuration?WT.mc_id=DT-MVP-4015686)
    -   [OpenSSH key management for Windows](https://learn.microsoft.com/en-us/windows-server/administration/openssh/openssh_keymanagement?WT.mc_id=DT-MVP-4015686)
-   PowerShell
    -   [Installing PowerShell on Windows](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell-on-windows?view=powershell-7.2&WT.mc_id=DT-MVP-4015686#msi)
    -   [PowerShell Remoting Over SSH - PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/learn/remoting/ssh-remoting-in-powershell-core?view=powershell-7.2&WT.mc_id=DT-MVP-4015686)
-   WinRM (Windows Remote Management)
    -   [Windows Remote Management - Win32 apps](https://learn.microsoft.com/en-us/windows/win32/winrm/portal?WT.mc_id=DT-MVP-4015686)
    -   [How to enable Windows Remote Shell](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/how-to-enable-windows-remote-shell?WT.mc_id=DT-MVP-4015686)
    -   [How To Copy Files Over WinRM With PowerShell - YouTube](https://www.youtube.com/watch?v=PAbfK6O9euo)
