# 如何在 Windows 安裝 Cygwin 的 SSHD 服務並正確使用 Rsync 同步檔案

我最近嘗試在 Windows 透過 Rsync 搭配 OpenSSH 備份檔案，結果怎樣都無法設定成功，直到今天才嘗試出一個可行的作法。雖然在 Windows 安裝 [Cygwin](https://www.cygwin.com/) + `cygsshd` 不是我心目中理想的解決方案，畢竟是開源且沒有技術支援的方案，出問題比較沒人可以救你，但這至少是一個可行方案。這篇文章將說明設定過程的完整步驟。

### 在 Windows 架設 Cygwin 的 OpenSSH Server 服務 (`cygsshd`)

> 請以系統管理人員身份執行 PowerShell 進行操作。

1.  安裝 [Chocolatey](https://chocolatey.org/install) 套件管理器
    
    ```powershell
    Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
    ```
    
2.  安裝 [Cygwin](https://www.cygwin.com/) 工具
    
    除了安裝 `cygwin` 之外，也建議安裝 `cyg-get` 工具，方便日後安裝套件：
    
    ```powershell
    choco install cygwin cyg-get -y
    ```
    
    > 預設安裝路徑為 `C:\tools\cygwin`
    
3.  透過 `cyg-get` 工具安裝必要套件
    
    ```powershell
    cyg-get rsync zstd libzstd cygrunsrv openssh
    ```
    
4.  透過**開始功能表**點擊 **Cygwin64 Terminal** 捷徑進入 Cygwin 殼層環境
    
5.  初始化 OpenSSH Server 設定
    
    執行 `ssh-host-config` 工具可以全自動完成所有必要設定
    
    ```bash
    ssh-host-config
    ```
    
    設定的過程會問你三個問題，依序回答 `yes`, `yes`, `Enter` 繼續即可：
    
    ```log
    *** Info: Generating missing SSH host keys
    ssh-keygen: generating new host keys: RSA DSA ECDSA ED25519
    
    *** Query: Should StrictModes be used? (yes/no) yes
    *** Info: Updating /etc/sshd_config file
    
    *** Query: Do you want to install sshd as a service?
    *** Query: (Say "no" if it is already installed as a service) (yes/no) yes
    
    *** Query: Enter the value of CYGWIN for the daemon: []
    
    *** Info: The sshd service has been installed under the LocalSystem
    *** Info: account (also known as SYSTEM). To start the service now, call
    *** Info: `net start cygsshd' or `cygrunsrv -S cygsshd'.  Otherwise, it
    *** Info: will start automatically after the next reboot.
    
    *** Info: Host configuration finished. Have fun!
    ```
    
    > 預設 `cygsshd` 服務會自動隨著 Windows 開機時自動啟動。
    
6.  啟動 `cygsshd` 服務
    
    你可以用 `net start cygsshd` 啟動服務
    
    ```bash
    net start cygsshd
    ```
    
    也可以透過 `cygrunsrv --start cygsshd` 命令啟動服務
    
    ```bash
    cygrunsrv --start cygsshd
    ```
    
7.  新增 `OpenSSH Server (cygsshd)` 防火牆規則
    
    ```bash
    New-NetFirewallRule -Name cygsshd -DisplayName 'OpenSSH Server (cygsshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
    ```
    

### 設定金鑰認證與無密碼登入

1.  先從 Windows Server 建立一個 `user1` 使用者
    
    ```powershell
    net user user1 * /ADD
    ```
    
2.  再從 Windows Client 安裝 [cwRsync](https://itefix.net/cwrsync) 工具
    
    我們將在 Windows 用戶端安裝 [cwRsync](https://itefix.net/cwrsync) 工具，但請注意，不要使用 Chocolatey 的 [cwRsync](https://community.chocolatey.org/packages/rsync) 套件進行安裝。
    
    ```powershell
    # 下載 cwRsync 最新版
    Invoke-WebRequest -Uri https://itefix.net/dl/free-software/cwrsync_6.2.4_x64_free.zip -OutFile cwrsync_6.2.4_x64_free.zip
    
    # 先解壓縮到暫存資料夾
    Expand-Archive -LiteralPath "$PWD\cwrsync_6.2.4_x64_free.zip" -DestinationPath "$env:TEMP\cwrsync"
    
    # 將 cwrsync_6.2.4_x64_free 目錄下所有檔案複製到 C:\cwrsync
    mkdir "C:\cwrsync"
    Copy-Item -Path "$env:TEMP\cwrsync\cwrsync_6.2.4_x64_free\*" -Destination "C:\cwrsync" -Recurse
    ```
    
    > 安裝好的 cwRsync 會在 `C:\cwrsync\bin` 看到 `rsync.exe`, `ssh.exe`, `ssh-keygen.exe`, `ssh-agent.exe` 等常用工具。
    
3.  設定無密碼的金鑰驗證
    
    從 Windows Client 產生一組 SSH 金鑰
    
    ```powershell
    C:\cwrsync\bin\ssh-keygen.exe -f 'mysshkey' -N '""'
    ```
    
    > 上述命令會產生兩個檔案，一個私密金鑰檔 `mysshkey` 與一個公開金鑰檔 `mysshkey.pub`
    
    ```bash
    # 第一次設定需建立合格的 .ssh/authorized_keys 檔案
    ssh user1@172.29.217.64 'mkdir .ssh; touch .ssh/authorized_keys; chmod 600 .ssh/authorized_keys'
    
    # 將公開金鑰檔內容複製過去
    cat ./mysshkey.pub | ssh user1@172.29.217.64 tee -a ~/.ssh/authorized_keys
    ```
    
    Windows 通常在建立好金鑰組之後會無法使用金鑰登入，因為 NTFS 權限可能有問題
    
    ```bash
    ssh -i ./mysshkey user1@172.29.217.64
    ```
    
    你會看到 `Permissions for './mysshkey' are too open.` 的錯誤訊息：
    
    ```
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    Permissions for './mysshkey' are too open.
    It is required that your private key files are NOT accessible by others.
    This private key will be ignored.
    Load key "./mysshkey": bad permissions
    user1@172.29.217.64's password:
    ```
    
4.  修正 SSH 金鑰權限
    
    由於**私密金鑰檔**的 NTFS 權限只能給「系統管理員」與「擁有者」可以讀取，所以有任何「其他使用者」也能讀取這個檔案，將無法通過 `ssh` 的安全檢查，因此無法使用 `publickey` 進行驗證。
    
    ```powershell
    # 查詢私密金鑰檔所有 NTFS 權限
    icacls .\mysshkey
    
    # 先移除 NTFS 檔案權限繼承
    icacls .\mysshkey /inheritance:r
    
    # 移除所有「非擁有者」的權限
    icacls .\mysshkey /remove Everyone
    icacls .\mysshkey /remove BUILTIN\Users
    icacls .\mysshkey /remove "NT AUTHORITY\Authenticated Users"
    icacls .\mysshkey /remove "NULL SID"
    
    # 先查詢擁有者是誰
    $owner=(Get-Acl .\mysshkey).owner
    
    # 允許擁有者可以完整存取該檔案
    icacls .\mysshkey /grant ${owner}:F
    
    # 查詢私密金鑰檔所有 NTFS 權限
    icacls .\mysshkey
    
    # 修正完 NTFS 權限就可以順利登入了
    ssh -i ./mysshkey user1@172.29.217.64
    ```
    

### 建立測試 rsync 透過 ssh 傳輸檔案

一般來說我們通常會這樣執行命令：

```powershell
rsync -avzr -e 'ssh -i .\mysshkey' mysshkey.pub user1@172.29.217.64:.
```

但是在我的電腦會看到以下錯誤：

```
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(228) [Receiver=3.2.4dev]
rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(228) [sender=3.2.3]
```

起初我以為是 `rsync` 版本不匹配導致，後來發現根本不是這麼一回事！

問題的主因主要是 `ssh.exe` 的匹配出了問題，你不能使用 [Win32-OpenSSH](https://github.com/PowerShell/Win32-OpenSSH) 的 `ssh.exe` 來跟 Rsync 搭配使用，直接使用 [cwRsync](https://itefix.net/cwrsync) 的 `ssh.exe` 即可！

以下才是正確的參數用法：

```powershell
rsync -avzr -e 'C:\cwrsync\bin\ssh.exe -i .\mysshkey' mysshkey.pub user1@172.29.217.64:.
```

以下是成功執行的顯示結果：

```
sending incremental file list
mysshkey.pub

sent 581 bytes  received 35 bytes  410.67 bytes/sec
total size is 571  speedup is 0.93
```

有了 Rsync 之後，你就可以輕鬆的實現 Windows 對 Windows 之間的自動備份方案，而且同時兼顧安裝設定的簡便性、網路傳輸的安全性，以及享受 rsync 帶來的強大檔案同步功能，有檔案差異比對、內容壓縮、與數十個可用的微調參數！ 👍

### 相關連結

-   [rsync](https://rsync.samba.org/)
-   [cwRsync - Rsync for Windows | itefix.net](https://www.itefix.net/cwrsync)
-   [Cygwin](https://cygwin.com/)
-   Chocolatey
    -   [Chocolatey Software | Cygwin 3.3.3](https://community.chocolatey.org/packages/cygwin)
    -   [Chocolatey Software | cyg-get 1.2.1](https://community.chocolatey.org/packages/cyg-get)
