Windows 11 接入 SSH 遠端控制:從 OpenSSH Server 到 TTS 中文朗讀的完整記錄
ASUS Ascent GX10控制的第四台: windows 介面的 NB
AI fleet 第 5 台入列:WinsonNB(Windows 11 25H2、Ryzen 7 5900HS、RTX 3050 Ti)透過 Tailscale + 內建 OpenSSH Server,GX10 可以免密登入、遠端跑指令、甚至叫它喇叭念「XXX ,起床了」。
跟 Android 那台(Termux)不同,Windows 的 SSH 是官方內建的,不需要第三方套件——但坑一個不少。全部記錄如下。
一、目標機
| 項目 | 值 |
|---|---|
| 型號 | WinsonNB(筆電) |
| 系統 | Windows 11 25H2(26200) |
| CPU | AMD Ryzen 9 5900HS(8C/16T) |
| GPU | NVIDIA RTX 3050 Ti + AMD Radeon 集顯 |
| RAM | 32 GB(實測時只剩 0.9 GB 可用,正有重任務在跑) |
| C 碟 | 288 GB NVMe,剩 169 GB |
| Tailnet | 100.95.23.8 |
二、四步接入(實際走過的順序)
步驟 1:啟用 OpenSSH Server
Win+X → PowerShell(管理員):
# 確認功能(可能已預裝)
Get-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 | Select-Object State
# 若 NotPresent:
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
# 啟動 + 自動
Set-Service -Name sshd -StartupType 'Automatic'
Start-Service sshd
# 確認監聽
Get-NetTCPConnection -State Listen | Where-Object {$_.LocalPort -eq 22}
確認:0.0.0.0:22 和 [::]:22 都 LISTENING(雙 stack 正常)。
⚠️ 排查小坑:用 netstat -ano | findstr ":22 " 會被其他埠號包含 22 的項目(如 22112)誤導,以為有在監聽——要用 Get-NetTCPConnection -State Listen | Where LocalPort -eq 22 才準。
步驟 2:防火牆
New-NetFirewallRule -Name sshd -DisplayName "OpenSSH Server (sshd)" -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22
不加這條,tailnet 的探測會直接 timeout(我們的實測:規則建好前 22 埠從 GX10 連 = timeout,建好後秒開)。
步驟 3:放公鑰(最大的坑,見第五節)
步驟 4:驗證
# GX10 端
ssh winso@100.95.23.8 'whoami; hostname'
# → winsonnb\winso / WinsonNB
三、遠端能力(全部實測)
| 能力 | 方式 | 驗證 |
|---|---|---|
| 跑指令 | ssh … "powershell -Command ..." |
✅ |
| 讀資源(CPU/RAM/GPU/碟) | WMI/CIM 指令 | ✅ 抓到 5900HS + RTX 3050 Ti |
| TTS 中文朗讀 | System.Speech.SpeechSynthesizer 內建,不需裝任何東西 |
✅ 喇叭實播「XXX,起床了」 |
| 檔案傳輸 | scp 雙向 | ✅ |
TTS 關鍵腳本(Windows 內建,免安裝)
Add-Type -AssemblyName System.Speech
$synth = New-Object System.Speech.Synthesis.SpeechSynthesizer
$synth.Speak("張瑞琪,起床了")
比 Android 的 termux-tts-speak 更乾淨——Windows 的 SAPI 聲音引擎選擇多(可選女聲/男聲/不同腔調)。
四、跟 Android 端對照
| 項目 | Android(vivo) | Windows 11 |
|---|---|---|
| SSH server | Termux openssh(第三方) | 內建 OpenSSH(官方) |
| 監聽埠 | 8022(慣例) | 22(標準) |
| 免密原理 | authorized_keys | authorized_keys(同一把) |
| TTS | termux-tts-speak | System.Speech(內建) |
| 重開機保持 | 手動 boot script(vivo 會殺) | systemd 對等:服務,穩 |
| 難度 | 7 坑 | 4 坑 |
| 拍相機 | termux-camera-photo ✅ | 要寫 MediaCapture(未做) |
五、踩坑記錄(4 個,依發生順序)
坑 1:netstat -ano | findstr ":22 " 的假陽性
- 現象:findstr 抓到
127.0.0.1:22112(某 app 的本地埠),以為 sshd 在監聽 - 解法:改用
Get-NetTCPConnection -State Listen | Where {$_.LocalPort -eq 22} - 教訓:shell 的 substring grep 是排查網路問題的第一陷阱
坑 2:Set-Content 預設 UTF-16 BOM
- 現象:公鑰檔「內容完全一樣」(hash 都算過)但 sshd 一律拒認
- 真相:Windows PowerShell 5.1 的
Set-Content預設用 UTF-16LE + BOM 寫檔,OpenSSH 不認 - 解法:重寫時加
-Encoding ASCII(公鑰是純 ASCII,安全) - 教訓:跨平台放金鑰,編碼要顯式聲明——Pi/手機都是 LF+UTF-8,Win 預設 CRLF+UTF-16
坑 3:粘貼又丟字元(老坑重演)
- 現象:92 vs 93 bytes,第三次出現這個問題了(手機那次是 92 vs 93)
- 解法:不再貼——GX10 開
python3 -m http.server,Win 上一行curl.exe -o ... http://100.69.83.97:port/id_ed25519.pub,SHA256 雙邊校驗(F3498230…995E67D一致) - 教訓:「長字串跨機器」一律走檔案傳輸 + 雜湊校驗。這已是第三台機器驗證的方法,可靠率 3/3。
坑 4(★最深★):管理員的公鑰根本不在 authorized_keys
- 現象:編碼修好了、hash 對了、權限收緊了(
icacls只留 winso/SYSTEM),還是 Permission denied,連續 4 次 - 真相:用
sshd.exe -d -o LogLevel=DEBUG前台跑除錯模式,一眼看到:
user winso matched group list administrators at line 87
trying public key file PROGRAMDATA/ssh/administrators_authorized_keys
Could not open authorized keys ... No such file or directory
Windows OpenSSH 的預設 sshd_config對管理員帳號有獨立規定:金鑰必須放C:\ProgramData\ssh\administrators_authorized_keys,根本忽略C:\Users\winso\.ssh\authorized_keys - 解法:
powershell
Copy-Item "$env:USERPROFILE\.ssh\authorized_keys" "$env:PROGRAMDATA\ssh\administrators_authorized_keys"
icacls "$env:PROGRAMDATA\ssh\administrators_authorized_keys" /setowner "BUILTIN\Administrators"
→ 一次過,ssh winso@100.95.23.8立刻登入成功 - 教訓:
- 卡住時,看 log 比猜快 100 倍——
sshd.exe -d -E file.log前台除錯模式,每條拒絕原因都寫得出來 - Windows 的管理員/一般使用者金鑰路徑不同,這個差異官方文件藏得很深
- 對一般使用者(非管理員),
~/.ssh/authorized_keys照常有效——這坑只咬管理員帳號
六、最終連線方式
# 任何 fleet 成員(或你任何裝置上裝 Tailscale):
ssh winso@100.95.23.8 # 免密, 22 埠
# 遠端跑 Powershell:
ssh winso@100.95.23.8 "powershell -NoProfile -Command 'hostname'"
七、fleet 全景(5 台)
| 裝置 | 角色 | 接入方式 |
|---|---|---|
| GX10 6679(100.69.83.97) | AI 大腦 | 本機 |
| Pi 5(192.168.1.236 / tailnet) | GPIO 現場控制 | SSH key |
| Pi 3(100.123.106.93) | 鏡面時鐘 | SSH key + systemd mm2.service |
| vivo V2248(100.117.225.79:8022) | 行動終端/相機 | Termux + sshd |
| WinsonNB(100.95.23.8:22) | Windows 桌面 + TTS | 內建 OpenSSH |
同一把公鑰(hermes-gx10,sha256 校驗)開五台門。任何一台上線,都能從 GX10 一鍵觸達。
八、總結
Windows 的 SSH 接入比 Android 簡單得多——官方套件、標準埠、官方 TTS。但坑的品質更高:UTF-16 編碼和管理員金鑰路徑這類問題,不出錯時一切正常,出錯時沒有任何提示,只能靠除錯模式 sshd + 讀 log破案。
核心教訓(全 fleet 通用,第三次驗證):
1. 長字串跨機器,永遠走檔案傳輸 + 雜湊校驗:Pi 3 / vivo / Win 三台,手貼失敗率 100%,HTTP 下載+SHA256 成功率 100%
2. 卡住時,啟用除錯模式看 log:比無限猜快幾個數量級
3. Windows 管理員 ≠ 一般使用者:SSH 金鑰路徑、icacls 權限模型都不同
下一步可以做的:Windows 版「遠端打雷」(同一支 WAV + Start-Process)、相機遠端拍攝(MediaCapture)、或把它接進 fleet 的排程(定時 TTS 叫起床)。
沒有留言:
張貼留言