---
# System prepended metadata

title: 在 Windows PowerShell 端建立 SSH 公鑰認證，免密碼登入 Ubuntu Server
tags: [Ubuntu Server]

---

# 在 Windows PowerShell 端建立 SSH 公鑰認證，免密碼登入 Ubuntu Server

- 伺服器：Ubuntu Server（固定 IP，例如 `192.168.X.XXX`）
- 用戶端：Windows 10/11（以 PowerShell 操作）
- 目標：使用公鑰認證(public key authentication)免密碼登入，並關閉密碼登入

## 前置條件
- Windows 需已安裝 OpenSSH Client（預設已內建，可在 PowerShell 執行 ssh -V 確認）
- Ubuntu 可連上 22/TCP（若有 UFW/防火牆，先允許：sudo ufw allow OpenSSH）

## 流程總覽

```mermaid
sequenceDiagram
  actor Win as Windows PowerShell
  participant U as Ubuntu Server

  Win->>U: 1) 使用密碼 ssh 你的userName@192.168.X.XXX 初次登入
  U-->>Win: 要求密碼並允許登入
  Win->>U: 2) 安裝 openssh-server（若未安裝）
  U-->>Win: sshd 服務啟動
  Win->>Win: 4) 產生本機 SSH 金鑰 (ed25519)
  Win->>U: 5) 傳送公鑰到 ~/.ssh/authorized_keys
  Win->>U: 7) 設定 sshd 僅允許金鑰、禁止 root 密碼
  U-->>Win: 重新載入 sshd 設定
  Win->>U: 6/8) 測試：金鑰可登入；密碼登入已被拒絕
```

## 詳細步驟

1) 先用密碼連線到 Ubuntu Server
在 PowerShell：
```powershell
ssh 你的userName@192.168.X.XXX
```
首次會提示是否信任指紋，輸入 yes，並輸入使用者密碼登入。

2) 安裝 OpenSSH Server（若已安裝可略過）
在 Ubuntu 端：
```bash
sudo apt update
sudo apt install -y openssh-server
sudo systemctl enable --now ssh
sudo systemctl status ssh --no-pager
```

3) 備份 sshd_config
在 Ubuntu 端：
```bash
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F_%H%M%S)
```

4) 在 Windows PowerShell 產生 SSH 金鑰
在 PowerShell：
```powershell
ssh-keygen -t ed25519 -a 100 -C "你的名稱@你的電腦"
# 產生：
# C:\Users\<你>\.ssh\id_ed25519        (私鑰 private key，請妥善保護)
# C:\Users\<你>\.ssh\id_ed25519.pub    (公鑰 public key，會放到伺服器)
```
說明：
- 註解(Comment)僅用於識別，例如 "alice@my-laptop" 或你的電子郵件。

5) 將公鑰傳到 Ubuntu 的 authorized_keys

**方法 A：使用 scp（建議）**
```powershell
$PUB="$env:USERPROFILE\.ssh\id_ed25519.pub"
scp $PUB 你的userName@192.168.X.XXX:~/id_ed25519.pub.tmp
ssh 你的userName@192.168.X.XXX "umask 077; mkdir -p ~/.ssh && chmod 700 ~/.ssh; touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys; cat ~/id_ed25519.pub.tmp >> ~/.ssh/authorized_keys; rm ~/id_ed25519.pub.tmp"
```

**方法 B：使用管線（處理 CRLF 問題）**
```powershell
$PUB="$env:USERPROFILE\.ssh\id_ed25519.pub"
type $PUB | ssh 你的userName@192.168.X.XXX "umask 077; mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys && tr -d '\r' >> ~/.ssh/authorized_keys"
```

6) 測試「只用公鑰」能否登入
請先保持你目前的 SSH 連線不要關閉，再開新視窗測試：
```powershell
ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no 你的userName@192.168.X.XXX
```
若成功即代表金鑰配置無誤。

7) 設定安全的 SSH 連線（建議使用方法 1）

**方法 1：建立優先權設定檔（推薦）**
```bash
sudo tee /etc/ssh/sshd_config.d/99-custom.conf << EOF
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
UsePAM yes
AuthenticationMethods publickey
EOF
```

**方法 2：編輯主設定檔**
```bash
sudo vim /etc/ssh/sshd_config
```
確認或加入以下設定：
```
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
UsePAM yes
AuthenticationMethods publickey
```

套用前先檢查語法並重新載入：
```bash
sudo sshd -t
sudo systemctl reload ssh
```

## 驗證設定

**檢查 SSH 伺服器的實際運行設定：**

```bash
sudo sshd -T | grep -Ei "(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|authenticationmethods)"
```

**期望輸出應該是：**
```
pubkeyauthentication yes
passwordauthentication no
kbdinteractiveauthentication no
authenticationmethods publickey
```

**若系統有 Match 區塊，使用更精確的檢查：**
```bash
sudo sshd -T -C user=你的userName,host=$(hostname),addr=192.168.X.XXX | grep -Ei "(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|authenticationmethods)"
```

8) 驗證密碼登入已被禁用
- 金鑰登入仍應成功：
  ```powershell
  ssh 你的userName@192.168.X.XXX
  ```
- 強制用密碼嘗試，應被拒絕：
  ```powershell
  ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no 你的userName@192.168.X.XXX
  ```
  看到 Permission denied 即為正確。

完成後，就可以在 Windows PowerShell 以 SSH 公鑰認證安全、免密碼地登入 Ubuntu Server，並且伺服器端已禁止密碼登入，降低被暴力破解的風險。

## 安全建議

1. **測試後再斷線**：在確認 SSH 金鑰登入正常運作之前，請保持至少一個 SSH 連線會話開啟。

2. **備份設定檔**：
   ```bash
   sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup
   ```

3. **監控登入日誌**：
   ```bash
   sudo tail -f /var/log/auth.log
   ```

4. **考慮使用額外的安全措施**：
   - 更改 SSH 預設埠號
   - 設定防火牆規則
   - 使用 fail2ban 防止暴力破解
   - 限制允許登入的使用者：
     ```bash
     # 在 sshd 設定中加入
     AllowUsers 你的userName
     # 或使用群組控制
     AllowGroups sshusers
     ```

## 常見問題：Cloud-init 設定覆蓋

### 問題描述

在 Ubuntu Server 22.04 中，即使在 `/etc/ssh/sshd_config` 中設定了 `PasswordAuthentication no`，使用 `sudo sshd -T` 檢查時可能仍然顯示 `passwordauthentication yes`，導致密碼登入依然被允許。

### 根本原因

現代 Ubuntu Server 預設包含 **Cloud-init** 系統，它會透過 `/etc/ssh/sshd_config.d/` 目錄中的設定檔覆蓋主要的 SSH 設定。

**SSH 設定檔的載入機制：**
1. OpenSSH 從上到下解析 `/etc/ssh/sshd_config`
2. 當遇到 `Include /etc/ssh/sshd_config.d/*.conf` 指令時，會在該位置展開所有 `.conf` 檔案（按字母順序）
3. 後出現的設定會覆蓋先前的設定
4. Ubuntu 22.04 預設在主設定檔開頭附近就有 Include 指令

### 為什麼全新安裝的 Linux 會有 Cloud-init？

現代 Linux 發行版（特別是 Ubuntu Server）預設包含 cloud-init，原因如下：

1. **雲端優先設計**：Ubuntu Server 針對雲端部署優化，即使在本地安裝也包含雲端工具
2. **統一映像檔**：使用相同的 ISO 映像檔部署到不同環境（本地、AWS、Azure、GCP 等）
3. **自動化需求**：即使在本地環境，也可能需要自動化配置功能

#### Cloud-init 的主要功能
```
初始開機時自動執行：
├── 網路設定 (IP、DNS、路由)
├── 使用者帳號建立與 SSH 金鑰配置
├── 套件安裝與更新
├── 檔案系統掛載與調整
├── SSH 服務設定 (包括認證方式)
├── 主機名稱設定
└── 執行自訂腳本
```

### 診斷步驟

**檢查是否存在 Include 設定和額外的設定檔：**

```bash
# 檢查主設定檔中的 Include 指令
grep -n "Include" /etc/ssh/sshd_config

# 列出額外的設定檔
ls -la /etc/ssh/sshd_config.d/

# 檢查 cloud-init 設定檔內容
cat /etc/ssh/sshd_config.d/50-cloud-init.conf
```

典型的 `50-cloud-init.conf` 內容可能包含：
```
PasswordAuthentication yes
```

### 解決方案

**方法 1：建立優先權更高的設定檔（推薦）**

sshd_config.d 的設定套用順序是按照字母順序排列的，後面的設定會覆蓋前面的設定：

```bash
sudo tee /etc/ssh/sshd_config.d/99-custom.conf << EOF
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin prohibit-password
AuthenticationMethods publickey
EOF

sudo sshd -t && sudo systemctl reload ssh
```

**方法 2：停用 Cloud-init SSH 設定檔**

如果是地端架設的 Ubuntu Server 且確定不需要 Cloud-init 的 SSH 管理：

```bash
sudo mv /etc/ssh/sshd_config.d/50-cloud-init.conf /etc/ssh/sshd_config.d/50-cloud-init.conf.disabled
sudo sshd -t && sudo systemctl reload ssh
```

### 驗證修正結果

```bash
# 確認設定已正確套用
sudo sshd -T | grep -Ei "(passwordauthentication|authenticationmethods|pubkeyauthentication)"

# 測試設定檔語法
sudo sshd -t

# 測試密碼登入（應被立即拒絕，不會提示輸入密碼）
ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no username@localhost
```

### 關於 PermitRootLogin 設定說明

- `PermitRootLogin no`：完全禁止 root 登入（包括金鑰登入）
- `PermitRootLogin prohibit-password`：禁止 root 密碼登入，但允許金鑰登入
- `PermitRootLogin yes`：允許 root 以任何方式登入（不建議）

### 補述：關於 Cloud-init

Cloud-init 是一個雲端環境初始化系統，用於在虛擬機器或容器啟動時自動執行配置。即使在本地安裝的 Ubuntu Server 也會包含此套件。

如果您的環境確定不需要 Cloud-init 功能，可以選擇：

**完全移除 Cloud-init：**
```bash
sudo apt remove --purge cloud-init
sudo rm -rf /etc/cloud/ /var/lib/cloud/
```

**或禁用 Cloud-init 的 SSH 模組：**
```bash
sudo vim /etc/cloud/cloud.cfg
# 在 cloud_config_modules 區段中註解掉：
# - ssh
```

**注意**：移除 Cloud-init 會影響雲端化引導流程與部分自動化工具，建議在本機/裸機長期使用且確定無需雲端初始化時再執行。