程開發(fā)實(shí)踐)
WSL2 裝好之后,大部分人停在能在 Windows 里敲 Linux 命令這一步就滿足了。但只要你有第二臺機(jī)器——哪怕只是同一張桌子上的另一臺筆記本、一臺平板,或者公司里那臺常年開著的編譯服務(wù)器——你很快就會碰到一個(gè)很具體的需求:我要從別的設(shè)備直接連進(jìn)這臺 WSL2,而不是每次都先遠(yuǎn)程桌面到 Windows 再開個(gè)終端窗口。這時(shí)候 NAT 模式就開始礙事了。這篇內(nèi)容講的就是我在這條路上來回折騰了幾輪之后沉淀下來的做法:把 WSL2 的網(wǎng)絡(luò)入口打通,用 SSH 作為統(tǒng)一入口,再讓 VSCode 的 Remote-SSH 直接落在這個(gè)入口上。適合已經(jīng)用過 WSL2、能看懂基本 Linux 命令、但被 IP 漂移和端口轉(zhuǎn)發(fā)折磨過的開發(fā)者;如果你剛裝完 WSL2,建議先跑通基礎(chǔ)環(huán)境再回來看,不然容易被細(xì)節(jié)淹沒。1. 先想清楚:我為什么要逃離 NAT 模式1.1 那個(gè)每次重啟都會變的 172 開頭的地址WSL2 默認(rèn)跑在一個(gè)輕量虛擬機(jī)里,Windows 主機(jī)構(gòu)建了一個(gè)虛擬網(wǎng)卡給它做 NAT 轉(zhuǎn)發(fā)。你在 WSL2 里執(zhí)行ip addr,大概率會看到eth0上掛著一個(gè)172.x.x.x的地址。這個(gè)地址不是你路由器分配的,是 WSL 內(nèi)部的虛擬 DHCP 給的,而且每次wsl --shutdown之后再啟動,它大概率會變。這就是一切麻煩的源頭。我最早的做法很樸素:需要從別的機(jī)器連進(jìn)來時(shí),先跳回 Windows 敲一遍wsl hostname -I把地址抄下來,再去另一臺機(jī)器上ssh user172.x.x.x。第一次還能忍,第三次就開始煩了,因?yàn)槟阌肋h(yuǎn)在重復(fù)同一件事,而且這個(gè)地址不能寫進(jìn)任何配置文件,更不能寫進(jìn)腳本——寫了第二天就失效。真正讓我下決心改造的,是我把一份構(gòu)建腳本扔到另一臺機(jī)器上跑,腳本里硬編碼了 WSL 的地址,隔天早上定時(shí)任務(wù)全線失敗。所以這里要先明確一個(gè)判斷標(biāo)準(zhǔn):如果你的使用場景里,連接發(fā)起方永遠(yuǎn)是 Windows 主機(jī)自己,那么 NAT 模式完全夠用,你甚至不需要任何額外配置,localhost轉(zhuǎn)發(fā)已經(jīng)幫你處理好了。只有當(dāng)連接發(fā)起方是別的設(shè)備或者別的容器時(shí),你才需要往下走。1.2 局域網(wǎng)里那臺設(shè)備連不進(jìn)來的真實(shí)原因很多人第一反應(yīng)是防火墻,關(guān)掉防火墻發(fā)現(xiàn)還是連不上,就懵了。其實(shí)原因很簡單:NAT 模式下,WSL2 的那臺虛擬機(jī)和你的物理局域網(wǎng)之間隔了一層地址轉(zhuǎn)換。局域網(wǎng)里的設(shè)備發(fā)包給 Windows 主機(jī)的 IP,Windows 收到了,但它不知道該轉(zhuǎn)發(fā)給內(nèi)部的哪臺虛擬機(jī),于是直接丟棄。這不是防火墻攔的,是壓根沒有路由規(guī)則。這就解釋了為什么在 Windows 主機(jī)上ssh localhost能通,換成ssh 192.168.1.x就不通——前者走的是 WSL 自己注冊的本地回環(huán)轉(zhuǎn)發(fā),后者走的是物理網(wǎng)卡,兩條路徑完全不同。理解這一點(diǎn)非常關(guān)鍵,后面所有方案的取舍都建立在它之上:我們要做的不是打開某個(gè)開關(guān),而是在 NAT 邊界上鑿一個(gè)洞,或者干脆換掉 NAT 這層結(jié)構(gòu)。順便說一個(gè)常見誤解:有人會去 WSL2 里執(zhí)行ip route看到默認(rèn)網(wǎng)關(guān)是172.x.x.1,就以為把這個(gè)網(wǎng)關(guān)改成路由器地址就能橋接。改完之后大概率是徹底斷網(wǎng),因?yàn)?WSL 的虛擬交換機(jī)不認(rèn)外部的 MAC 和路由,恢復(fù)起來還得wsl --shutdown重來。這條路我試過,浪費(fèi)時(shí)間,不建議。2. 三條技術(shù)路線的真實(shí)取舍,別在錯(cuò)誤的方向上耗時(shí)間2.1 端口轉(zhuǎn)發(fā):最土但最可控的方案netsh interface portproxy是 Windows 自帶的端口轉(zhuǎn)發(fā)工具,原理是在 Windows 主機(jī)上監(jiān)聽一個(gè)端口,把流量轉(zhuǎn)發(fā)到 WSL2 的內(nèi)部地址。命令長這樣,需要管理員權(quán)限的 PowerShell:# 假設(shè) WSL2 當(dāng)前地址是 172.28.100.5,想把宿主機(jī)的 2222 端口轉(zhuǎn)到 WSL 的 22 netsh interface portproxy add v4tov4 listenport2222 listenaddress0.0.0.0 connectport22 connectaddress172.28.100.5配套還要放行防火墻:New-NetFirewallRule -DisplayName WSL SSH 2222 -Direction Inbound -Protocol TCP -LocalPort 2222 -Action Allow這個(gè)方案最大的優(yōu)點(diǎn)是不改變?nèi)魏尉W(wǎng)絡(luò)結(jié)構(gòu),失敗了刪掉規(guī)則就恢復(fù)原樣,風(fēng)險(xiǎn)極低。缺點(diǎn)是它把IP 會變這個(gè)問題原封不動地留給了你:WSL 重啟、地址變了,轉(zhuǎn)發(fā)規(guī)則還指向舊地址,連接就會超時(shí),而且超時(shí)的表現(xiàn)和服務(wù)沒起來幾乎一模一樣,排查起來很迷惑。我的處理辦法是寫一個(gè)開機(jī)腳本,每次 WSL 啟動后自動刷新轉(zhuǎn)發(fā)規(guī)則。核心邏輯就是取當(dāng)前地址、刪舊規(guī)則、加新規(guī)則。這個(gè)腳本我放在任務(wù)計(jì)劃里,登錄時(shí)觸發(fā)。它不優(yōu)雅,但運(yùn)行了一年多沒出過問題,原因很簡單:它把不確定性收斂到了一個(gè)地方,你只需要盯住這一個(gè)腳本有沒有跑成功。2.2 鏡像網(wǎng)絡(luò)模式:最接近橋接體驗(yàn)的官方路子如果你用的是較新的 Windows 11 和較新的 WSL 版本,有一個(gè)更干凈的選擇:鏡像網(wǎng)絡(luò)模式(mirrored networking)。它讓 WSL2 直接復(fù)用 Windows 主機(jī)的網(wǎng)絡(luò)接口和地址,不再單獨(dú)做一層 NAT。開啟方式是在用戶目錄下建一個(gè).wslconfig文件,路徑是C:\Users\你的用戶名\.wslconfig,內(nèi)容:[wsl2] networkingModemirrored保存后執(zhí)行wsl --shutdown,等幾秒再啟動,進(jìn)去ip addr,你會發(fā)現(xiàn)網(wǎng)絡(luò)接口變了,地址和 Windows 主機(jī)在同一網(wǎng)段。此時(shí)在 WSL2 里跑的服務(wù),Windows 上用localhost:端口能直接訪問,局域網(wǎng)里的其他設(shè)備用Windows 主機(jī)的 IP 端口也能直接訪問,不需要任何portproxy規(guī)則。這個(gè)模式之所以被很多人叫作橋接,是因?yàn)閺氖褂皿w驗(yàn)上看它確實(shí)達(dá)到了橋接的效果:同一網(wǎng)段、可直接被外部訪問、不用轉(zhuǎn)發(fā)。但從實(shí)現(xiàn)上說它不是二層橋接,只是把主機(jī)的網(wǎng)絡(luò)棧共享給了 WSL。這個(gè)區(qū)別在實(shí)際使用中通常無關(guān)緊要,但在排查問題時(shí)很重要——比如你會發(fā)現(xiàn) WSL 里看到的網(wǎng)卡列表和 Windows 上高度一致,包括那些虛擬網(wǎng)卡,這就是共享網(wǎng)絡(luò)棧的直接體現(xiàn)。鏡像模式有一個(gè)必須注意的前提:它要求較新的 WSL 版本??梢韵扰躻sl --version看一眼,如果命令本身報(bào)錯(cuò)說不認(rèn)識,說明版本偏舊,先升級。另外在某些企業(yè)環(huán)境里,主機(jī)的網(wǎng)絡(luò)策略或安全軟件會對這種共享?xiàng)5男袨橛蓄~外限制,表現(xiàn)是開起來之后主機(jī)自己斷網(wǎng)了,遇到這種情況直接改回默認(rèn)模式,別硬剛。2.3 想用 Hyper-V 外部虛擬交換機(jī)做真橋接?我勸你放棄網(wǎng)上不少教程會告訴你:打開 Hyper-V 管理器,創(chuàng)建一個(gè)外部虛擬交換機(jī)綁定物理網(wǎng)卡,然后把 WSL 的虛擬網(wǎng)卡掛上去,這樣就實(shí)現(xiàn)了真正的橋接。這個(gè)說法在早期的 Hyper-V 虛擬機(jī)上成立,但在 WSL2 上基本行不通。原因是 WSL2 的虛擬網(wǎng)卡由 WSL 自己管理,并不會以可以隨意掛載到外部交換機(jī)的形式暴露出來,你在 Hyper-V 管理器里往往找不到對應(yīng)的可操作對象。更糟的是,一旦你在 Hyper-V 里創(chuàng)建了綁定物理網(wǎng)卡的外部交換機(jī),Windows 主機(jī)的網(wǎng)絡(luò)配置可能被改寫,輕則 IP 變了,重則直接斷網(wǎng),而恢復(fù)過程需要刪掉交換機(jī)、重置網(wǎng)卡,有時(shí)候還得重啟。我在這上面栽過一次,當(dāng)時(shí)以為是自己操作不對,反復(fù)試了三遍,每次都把主機(jī)網(wǎng)絡(luò)搞掛,最后確認(rèn)這條路在 WSL2 上就是不成立的。把三條路線放在一起對比,結(jié)論就很清楚了:方案外部設(shè)備可訪問IP 是否穩(wěn)定對主機(jī)網(wǎng)絡(luò)的侵入性恢復(fù)難度適用場景netsh 端口轉(zhuǎn)發(fā)是,但要放行防火墻否,需腳本刷新低,僅增加轉(zhuǎn)發(fā)規(guī)則刪規(guī)則即可老版本系統(tǒng)、企業(yè)受限環(huán)境鏡像網(wǎng)絡(luò)模式是,直接可達(dá)是,跟隨主機(jī)地址中,改變網(wǎng)絡(luò)棧結(jié)構(gòu)改回配置重啟新版本系統(tǒng),首選Hyper-V 外部交換機(jī)理論可行,實(shí)際難不確定高,可能打斷主機(jī)網(wǎng)絡(luò)高,常需重啟修復(fù)不建議我的實(shí)際選擇是:主力機(jī)用鏡像網(wǎng)絡(luò)模式,備用機(jī)上留一套端口轉(zhuǎn)發(fā)腳本兜底。兩套方案并存聽起來冗余,但正是這套冗余讓我在換機(jī)器、重裝系統(tǒng)、版本回退的幾種情況下都沒有卡住過。3. 讓 sshd 在 WSL2 里真正跑起來并活過重啟3.1 安裝與 sshd_config 里真正需要改的那幾行網(wǎng)絡(luò)通了只是修好了路,還得有個(gè)服務(wù)在門口收件。WSL2 的發(fā)行版里默認(rèn)通常沒裝 SSH 服務(wù)端,先裝:sudo apt update sudo apt install -y openssh-server裝完之后先別急著改配置,直接sudo service ssh start,然后在 Windows 上試著連一次。先跑通默認(rèn)配置,再逐項(xiàng)加固,這個(gè)順序很重要。我見過太多人一上來就把PermitRootLogin、PasswordAuthentication、AllowUsers全改了,結(jié)果連不上,還得回頭一項(xiàng)項(xiàng)排查到底是哪一行出的問題。默認(rèn)配置跑通之后,打開/etc/ssh/sshd_config,真正需要動的其實(shí)就三處:# 明確監(jiān)聽所有地址,排除只綁回環(huán)的可能 ListenAddress 0.0.0.0 # 端口按需改,避開 Windows 主機(jī)上可能已被占用的 22 Port 2222 # 密鑰登錄為主,密碼登錄視安全要求關(guān)閉 PubkeyAuthentication yes PasswordAuthentication no這里解釋一下為什么把端口改掉。Windows 10/11 自帶一個(gè)可選的 OpenSSH Server 功能,如果你之前手滑裝過并啟用了它,Windows 側(cè)的 22 端口就被占了。此時(shí)你在 WSL 里也開 22,再用端口轉(zhuǎn)發(fā)或者鏡像模式,就會出現(xiàn)連接上了但認(rèn)證的是 Windows 那個(gè)服務(wù)的詭異現(xiàn)象——表現(xiàn)是用戶名密碼怎么輸都不對,而且報(bào)錯(cuò)信息完全看不出是連錯(cuò)了地方。換一個(gè)非標(biāo)準(zhǔn)端口(2222、2202之類)能一勞永逸地躲開這個(gè)坑。改完配置先用sudo sshd -t做語法檢查,這個(gè)命令只校驗(yàn)不啟動,能提前發(fā)現(xiàn)拼寫錯(cuò)誤。確認(rèn)無誤再重啟服務(wù)。3.2 密鑰登錄:那兩個(gè)權(quán)限數(shù)字比密鑰本身更容易出錯(cuò)生成密鑰對在 Windows 側(cè)做就行,ssh-keygen -t ed25519 -f $HOME\.ssh\id_ed25519_wsl,然后把公鑰內(nèi)容追加到 WSL2 里的~/.ssh/authorized_keys。這一步看起來簡單,但權(quán)限問題幾乎人人都踩過。OpenSSH 對權(quán)限的檢查非常嚴(yán)格,而且它的檢查邏輯在服務(wù)端:如果~/.ssh或authorized_keys的權(quán)限過于寬松(比如組用戶或其他用戶可寫),它會靜默拒絕使用這個(gè)密鑰,日志里可能只有一句很含糊的 Authentication refused: bad ownership or modes。修復(fù)方式:chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys還有兩個(gè)容易忽略的點(diǎn)。第一,~/.ssh的所有上級目錄也不能對組用戶或其他用戶可寫,如果你把家目錄權(quán)限改成了777,密鑰同樣會失效。第二,如果 WSL2 里的用戶是通過 Windows 用戶映射進(jìn)來的,注意authorized_keys要放在實(shí)際登錄用戶的家目錄下,而不是 root 的目錄下。我見過有人把公鑰追加到了sudo之后的 root 家目錄,然后一直困惑為什么用普通用戶登錄不進(jìn)去。密鑰驗(yàn)證是否真的生效,有個(gè)快速判斷方法:ssh -v看輸出里有沒有Offering public key以及緊隨其后的Server accepts key。如果只有前者沒有后者,基本就是服務(wù)端權(quán)限檢查沒過;如果連前者都沒有,說明客戶端的IdentityFile路徑寫錯(cuò)了。這個(gè)二分法能省掉大量瞎猜的時(shí)間。3.3 開機(jī)自啟:別指望手動service ssh startWSL2 的實(shí)例在你不使用時(shí)會自動休眠,下次訪問時(shí)重新拉起。這意味著你手動start的 sshd,在下一次實(shí)例重啟后就不在了。表現(xiàn)是今天配好了,明天早上連不上,進(jìn)去一看進(jìn)程沒了。這個(gè)問題如果不解決,整套配置就是一次性的。兩種接管方式。第一種是啟用 systemd,在/etc/wsl.conf里寫:[boot] systemdtrue保存后wsl --shutdown,重進(jìn),systemctl status能正常輸出就說明 systemd 起來了,然后sudo systemctl enable --now ssh即可實(shí)現(xiàn)開機(jī)自啟。這是目前更推薦的方式,因?yàn)楹芏嗥渌?wù)也依賴 systemd。第二種是不啟用 systemd,直接用wsl.conf的 boot 命令:[boot] command service ssh start這個(gè)方式更輕,不改變 init 系統(tǒng),適合那些不想動 systemd 的環(huán)境。缺點(diǎn)是它只能執(zhí)行單條命令,想同時(shí)啟動多個(gè)服務(wù)就得包一層腳本。我的建議是:如果你的發(fā)行版和 WSL 版本支持 systemd,就用 systemd。理由不是 systemd 更好,而是生態(tài)更一致——你在別的 Linux 機(jī)器上學(xué)到的systemctl enable經(jīng)驗(yàn)可以直接復(fù)用,不用為 WSL 單獨(dú)記一套。4. 把 VSCode 的 Remote-SSH 接到這個(gè)入口上4.1 config 文件怎么寫才不用每次輸一堆參數(shù)VSCode 的 Remote-SSH 擴(kuò)展讀取的是標(biāo)準(zhǔn) SSH 配置文件,Windows 側(cè)路徑是C:\Users\用戶名\.ssh\config。寫好之后 VSCode 左側(cè)遠(yuǎn)程資源管理器里會直接列出這個(gè)主機(jī)名,點(diǎn)一下就能連:Host wsl-dev HostName 127.0.0.1 Port 2222 User devuser IdentityFile ~/.ssh/id_ed25519_wsl ServerAliveInterval 30 ServerAliveCountMax 3這里有幾個(gè)參數(shù)值得說明。HostName填127.0.0.1是配合端口轉(zhuǎn)發(fā)或鏡像模式的寫法,因?yàn)樽罱K暴露端口的是 Windows 主機(jī);如果你走的是純局域網(wǎng)直連,就填主機(jī)的局域網(wǎng) IP。ServerAliveInterval 30是每 30 秒發(fā)一次心跳,配合ServerAliveCountMax 3,能在網(wǎng)絡(luò)短暫抖動時(shí)避免連接被判定為斷開——WSL2 實(shí)例休眠再喚醒的場景下,這個(gè)設(shè)置能顯著減少連接已關(guān)閉的提示頻率。IdentityFile里的~在 Windows 的 SSH 客戶端下會解析到用戶目錄,一般沒問題,但如果你在 VSCode 里遇到找不到密鑰的報(bào)錯(cuò),直接改成絕對路徑C:/Users/xxx/.ssh/id_ed25519_wsl,注意用正斜杠。還有一個(gè)細(xì)節(jié):改完 config 之后,如果連接行為沒變化,可能是 VSCode 緩存了舊配置。這時(shí)候執(zhí)行一次命令面板里的Remote-SSH: Kill VS Code Server on Host,清掉遠(yuǎn)端的服務(wù)端進(jìn)程,再重連,通常就恢復(fù)正常了。4.2 首次連接會遇到的三道坎第一道是 host key 確認(rèn)。首次連接會彈出一個(gè)指紋確認(rèn),選繼續(xù)即可。但如果你之前用同一個(gè) IP 和端口連過別的機(jī)器,會遇到REMOTE HOST IDENTIFICATION HAS CHANGED的硬性拒絕。這是因?yàn)榕f指紋還留在known_hosts里。處理方式是ssh-keygen -R [127.0.0.1]:2222,注意帶端口時(shí)要加方括號和引號,不帶端口的話格式不同,寫錯(cuò)了刪不掉。這個(gè)報(bào)錯(cuò)看起來嚇人,實(shí)際上是保護(hù)機(jī)制在正常工作,不用緊張。第二道是遠(yuǎn)端服務(wù)端安裝。Remote-SSH 連接成功后,會在遠(yuǎn)端自動下載并安裝一個(gè)輕量的服務(wù)端組件。這個(gè)過程需要遠(yuǎn)端能訪問下載源。如果 WSL2 里的網(wǎng)絡(luò)出口有問題,就會卡在 Setting up SSH Host 這一步很久最后失敗。遇到這種情況,可以看 VSCode 的輸出面板里 Remote-SSH 通道的具體報(bào)錯(cuò),通常會給出下載地址和失敗原因。實(shí)在裝不上,也可以手動把安裝包放進(jìn)遠(yuǎn)端指定目錄,不過這條路比較繞,優(yōu)先解決網(wǎng)絡(luò)出口問題。第三道是擴(kuò)展的安裝位置。這是新手最容易困惑的地方:Remote-SSH 連上之后,你的工作區(qū)在遠(yuǎn)端,大部分?jǐn)U展需要安裝到遠(yuǎn)端。在擴(kuò)展面板里,已安裝的擴(kuò)展會顯示一個(gè)在 SSH: wsl-dev 上安裝的按鈕,點(diǎn)一下才會在遠(yuǎn)端生效。像語言服務(wù)、調(diào)試器、格式化工具這些必須裝遠(yuǎn)端;主題、快捷鍵這類界面相關(guān)的裝本地就行。搞混了的表現(xiàn)是擴(kuò)展明明裝了但就是不工作,排查半天發(fā)現(xiàn)裝錯(cuò)了位置。4.3 WSL 擴(kuò)展和 Remote-SSH,到底該用哪個(gè)這里必須說清楚一個(gè)容易混淆的點(diǎn):VSCode 有一個(gè)官方的 WSL 擴(kuò)展,它直接對接 WSL2 實(shí)例,不需要 SSH,也不需要網(wǎng)絡(luò)配置,打開文件夾時(shí)選 Connect to WSL 就行。那既然有這個(gè),為什么還要折騰 Remote-SSH?答案是使用場景不同。WSL 擴(kuò)展要求 VSCode 跑在 Windows 主機(jī)上,它通過本地管道和 WSL 通信。如果你的開發(fā)機(jī)就是這臺 Windows,那 WSL 擴(kuò)展是更省事的選擇,網(wǎng)絡(luò)部分完全不用管。但如果你的場景是:代碼跑在 A 機(jī)器的 WSL2 里,而你在 B 機(jī)器上寫代碼,那 WSL 擴(kuò)展就無能為力了,因?yàn)樗荒苓B本機(jī)的 WSL。這時(shí)候 Remote-SSH 才是正解,因?yàn)樗举|(zhì)上是通過 SSH 連一臺 Linux 機(jī)器,至于那臺機(jī)器是物理機(jī)、虛擬機(jī)還是 WSL2,它并不關(guān)心。我自己的用法是兩者并存:坐在主力機(jī)前的時(shí)候,用 WSL 擴(kuò)展,啟動快、零配置;出門用筆記本的時(shí)候,用 Remote-SSH 連回主力機(jī)的 WSL2。兩個(gè)入口指向同一份代碼,互不干擾。需要注意的是,不要在兩邊同時(shí)打開同一個(gè)項(xiàng)目并同時(shí)修改,雖然不會立刻沖突,但文件監(jiān)聽和自動格式化可能互相打架,造成難以復(fù)現(xiàn)的奇怪問題。5. 那些讓我卡了半天的坑,以及我的排查順序5.1 服務(wù)在跑但連不上:從監(jiān)聽地址開始查最典型的現(xiàn)象:WSL2 里ps aux | grep sshd明明有進(jìn)程,service ssh status也說 running,但外面就是連不上。這時(shí)候別急著懷疑網(wǎng)絡(luò),先確認(rèn)它到底監(jiān)聽在哪個(gè)地址上:ss -tlnp | grep sshd如果輸出是127.0.0.1:2222而不是0.0.0.0:2222或[::]:2222,那問題就找到了——它只監(jiān)聽回環(huán),外部流量進(jìn)不來。原因通常是sshd_config里有ListenAddress 127.0.0.1的殘留,或者被某個(gè)覆蓋配置改掉了。改成0.0.0.0重啟即可。我的排查順序固定為四步,基本能覆蓋九成情況:第一步看監(jiān)聽地址(ss -tlnp),第二步從本機(jī)連一次(ssh -p 2222 user127.0.0.1,排除認(rèn)證問題),第三步從 Windows 連一次(區(qū)分是 WSL 內(nèi)部問題還是轉(zhuǎn)發(fā)問題),第四步從局域網(wǎng)第三臺設(shè)備連一次(區(qū)分是主機(jī)防火墻問題還是路由問題)。每一步只增加一個(gè)變量,這樣一旦某一步失敗,問題范圍立刻縮小一半。5.2 開了鏡像模式,宿主機(jī)反而連不上了這個(gè)坑很反直覺:改配置之前l(fā)ocalhost能連,改成鏡像模式之后反而連不上了。原因通常是端口沖突——鏡像模式下,WSL2 和 Windows 主機(jī)共享網(wǎng)絡(luò)端口空間,如果 Windows 上已經(jīng)有進(jìn)程占了那個(gè)端口(比如前面提過的 Windows 自帶 SSH 服務(wù)占了 22),WSL 里的服務(wù)就綁不上,或者綁上了但流量被 Windows 那個(gè)進(jìn)程接走了。驗(yàn)證方法很直接:在 Windows 上netstat -ano | findstr :2222,看有沒有別的 PID 占著。有的話要么換端口,要么把占用進(jìn)程停掉。我現(xiàn)在的習(xí)慣是給 WSL 的 SSH 固定用一個(gè)不常見的端口,徹底避開這類沖突,省得每次都要查。還有一種情況是防火墻的配置文件區(qū)分。Windows 防火墻對專用網(wǎng)絡(luò)和公用網(wǎng)絡(luò)的規(guī)則是分開的,你放行了專用網(wǎng)絡(luò),但當(dāng)前網(wǎng)卡被識別成公用網(wǎng)絡(luò),規(guī)則就不生效。表現(xiàn)是主機(jī)自己能連、局域網(wǎng)連不上。檢查方式是看網(wǎng)絡(luò)屬性里的配置文件類型,如果顯示公用,要么切換成專用,要么在防火墻規(guī)則里把公用網(wǎng)絡(luò)也勾上。5.3 IP 漂移導(dǎo)致的間歇性失敗,以及我怎么把它固定下來端口轉(zhuǎn)發(fā)方案下,最煩的不是配置麻煩,而是它會在你完全沒預(yù)期的時(shí)候失效。某天早上連不上,進(jìn)去一看,WSL 地址從172.28.100.5變成了172.30.200.8,轉(zhuǎn)發(fā)規(guī)則還指著舊地址。這種失敗沒有任何報(bào)錯(cuò)提示,只有超時(shí),很容易誤判成服務(wù)掛了。我的解決辦法是把刷新邏輯寫成一個(gè) PowerShell 腳本,登錄時(shí)自動執(zhí)行:$wslIp (wsl hostname -I).Trim().Split( )[0] if ($wslIp) { netsh interface portproxy delete v4tov4 listenport2222 listenaddress0.0.0.0 2$null netsh interface portproxy add v4tov4 listenport2222 listenaddress0.0.0.0 connectport2222 connectaddress$wslIp Write-Output 已刷新轉(zhuǎn)發(fā)規(guī)則 - $wslIp }這個(gè)腳本的關(guān)鍵在于先刪后加,因?yàn)閍dd一個(gè)已存在的規(guī)則會報(bào)錯(cuò),而delete一個(gè)不存在的規(guī)則也會報(bào)錯(cuò),所以用2$null把刪除時(shí)的噪音吞掉。腳本執(zhí)行完可以用netsh interface portproxy show all確認(rèn)當(dāng)前規(guī)則指向的地址是不是最新的。說到底,這個(gè)腳本解決的不是技術(shù)問題,而是把需要人工記住的事變成機(jī)器自動做的事。這類自動化在小規(guī)模環(huán)境里往往被忽略,覺得手動改一下也就半分鐘,但半分鐘乘以一年兩百次,加上每次都要重新回憶命令語法的時(shí)間成本,賬就不一樣了。6. 跑穩(wěn)之后我把配置固化下來的幾個(gè)習(xí)慣配置這東西,只要不落到文件里,過三個(gè)月自己都想不起來當(dāng)初改了什么。我現(xiàn)在給自己定了兩條規(guī)矩:第一,所有非默認(rèn)的改動都寫進(jìn)版本管理的 dotfiles 倉庫,包括.wslconfig、sshd_config的差異部分、Windows 側(cè)的 SSH config 和那個(gè)刷新腳本;第二,在倉庫根目錄放一個(gè)README,只寫為什么這么配而不寫怎么配,因?yàn)樵趺磁渚W(wǎng)上到處都有,為什么這么配才是三個(gè)月后真正需要的信息。具體到版本管理,sshd_config我不直接覆蓋系統(tǒng)文件,而是維護(hù)一份片段,用的時(shí)候手動合并或用配置片段目錄加載。這樣做的好處是系統(tǒng)升級時(shí)不會因?yàn)槲募桓倪^而彈出一堆交互詢問。.wslconfig直接在倉庫里放一份完整版本,換機(jī)器時(shí)拷過去就行,內(nèi)容少,維護(hù)成本低。還有一個(gè)容易被忽略的固化點(diǎn):把驗(yàn)證步驟寫成腳本。我寫了一個(gè)很短的健康檢查腳本,依次檢查 sshd 進(jìn)程、監(jiān)聽地址、Windows 側(cè)轉(zhuǎn)發(fā)規(guī)則、防火墻規(guī)則是否存在,全部通過就打印一行 OK。每次換機(jī)器或者系統(tǒng)大版本更新后跑一遍,比手動一項(xiàng)項(xiàng)確認(rèn)快得多,也避免了以為配好了其實(shí)漏了一步的尷尬。最后分享一個(gè)我在反復(fù)重裝中總結(jié)出來的小經(jīng)驗(yàn):先跑通最小路徑,再逐層加固。最小路徑指的是:默認(rèn) sshd 配置 密碼登錄 端口轉(zhuǎn)發(fā),能在另一臺機(jī)器上ssh進(jìn)去看到提示符,這一步通了,后面所有的密鑰、端口改號、systemd 接管、鏡像模式,都只是在這條已驗(yàn)證的路徑上做替換,任何一步出問題都可以立刻回退到上一步可用的狀態(tài)。反過來,如果一上來就把所有優(yōu)化項(xiàng)全堆上去,一旦不通,你面對的是一堆未知變量的組合,排查成本會翻好幾倍。這套思路我在別的環(huán)境配置上也一直在用,屢試不爽。