|
|
WireGuard 幾乎不給錯誤訊息。連不上的時候它不會說「密碼錯誤」也不會說「連線逾時」,就是安靜地什麼都沒發生。
所以只能靠排除。這篇的每一步都設計成一個二選一的判定:下一個指令,看一個輸出,得到「往左走」或「往右走」,不是「可能是這個也可能是那個」。

這篇假設的環境
- 家裡的內網 `192.168.88.0/24`,伺服器在 `192.168.88.20`(Linux / Docker)或是路由器自己(RouterOS)
- 隧道網段 `10.20.30.0/24`
- 對外位址 `114.32.80.149`,WireGuard 聽在 UDP `51820`
你的數字不一樣的話,下面每個指令裡的對應位置都要換掉。
⚠ 開始之前:測試一定要在家門外
人在家裡、連著自家 Wi-Fi 的時候測 VPN,測到的東西沒有意義:流量根本沒出過家門,而且多數路由器不支援「從內部連自己的對外 IP」(叫做 NAT 回流)。
把手機的 Wi-Fi 關掉、用行動網路。 這一句解決掉的案例比底下七步加起來還多。
---
步驟 1:先看有沒有交握,決定要往哪半邊查
在伺服器上:
- # Linux / Docker 容器裡
- sudo wg show
- # RouterOS
- /interface/wireguard/peers/print detail
複製代碼
你會看到(Linux 版):
- interface: wg0
- public key: xTIBA8dJ+YbXQ9r2vKcN0mFe7sLpQwZ3hYuGaVcRtE4=
- listening port: 51820
- peer: 9kLm2XpQwErTyUiOp3AsDfGhJkL5ZxCvBnM8QwE=
- endpoint: 203.0.113.88:41235
- allowed ips: 10.20.30.2/32
- latest handshake: 43 seconds ago
- transfer: 380.21 KiB received, 1.24 MiB sent
複製代碼
照這三種結果分岔:
- 完全沒有 `latest handshake` 這一行(RouterOS 是 `last-handshake` 空白) → 從來沒連上過,往步驟 2
- 有時間,但是好幾個小時或好幾天前 → 曾經通過,現在斷了。往步驟 2,同時先檢查用戶端設定檔有沒有 `PersistentKeepalive = 25`,沒有的話補上再測
- 有時間,而且是幾秒到兩分鐘前 → 隧道本身是好的,問題在路由或 DNS,直接跳步驟 5
⚠ 交握時間在兩分鐘上下跳動是正常的。WireGuard 在有流量的時候大約每兩分鐘重新交握一次,沒流量就不動。看到「1 分 50 秒前」不要以為快斷了。
---
步驟 2:封包到底有沒有抵達伺服器(整篇最重要的一刀)
「沒有交握」這個狀態底下藏著兩個完全不同的世界:封包根本沒到(問題在網路路徑上),或是封包到了但談不攏(問題在金鑰設定上)。
不先切開的話,你會一直在改金鑰,而封包連門都沒進來。
在伺服器上開著這個指令:
- # Linux / Docker 主機
- sudo tcpdump -ni any udp port 51820
- # RouterOS:改用防火牆規則的計數器
- /ip/firewall/filter/print stats where comment="WireGuard"
複製代碼
然後用手機(行動網路)把 WireGuard 打開。
你會看到(Linux 版,有封包進來的話):
- 09:41:02.183045 IP 203.0.113.88.41235 > 192.168.88.20.51820: UDP, length 148
- 09:41:07.245113 IP 203.0.113.88.41235 > 192.168.88.20.51820: UDP, length 148
- 09:41:12.301882 IP 203.0.113.88.41235 > 192.168.88.20.51820: UDP, length 148
複製代碼
RouterOS 版的話是 `PACKETS` 那一欄的數字在增加。
兩種結果:
- 有封包進來(每隔約 5 秒一筆,`length 148` 是交握的第一個封包)→ 網路路徑是通的,往步驟 4
- 一片空白,手機按了十幾秒也沒有任何一行 → 封包沒到,往步驟 3
⚠ 只有「送出去」沒有「回來」也算有到。上面的輸出如果只有 `> 192.168.88.20.51820` 的方向、沒有反方向,代表伺服器收到了但沒回應 —— 那是步驟 4 的金鑰問題,不是路徑問題。
⚠ 不要用線上的「埠掃描」工具來判斷。那些工具全部測 TCP,而 WireGuard 走 UDP。它們一定會告訴你「51820 是關閉的」,而那個結論是錯的。上面的 `tcpdump` 是唯一可信的判準。
---
步驟 3:封包沒到,四個原因依序排除
3-1 你是不是在 CGNAT 後面
在路由器的管理頁上找到 WAN IP(廣域網路 IP),跟外面看到的 IP 比對:
- curl -4 ifconfig.me; echo
複製代碼
兩個不一樣,或是 WAN IP 落在下面任何一段:
- 10.0.0.0 ~ 10.255.255.255
- 172.16.0.0 ~ 172.31.255.255
- 192.168.0.0 ~ 192.168.255.255
- 100.64.0.0 ~ 100.127.255.255 <- 這段是 CGNAT 專用
複製代碼
→ 你根本沒有一個外面連得進來的門牌,埠轉發做了也是白做。這不是設定錯,是你沒有那個東西。三條路:
- 中華電信 HiNet:申請「非固定制固定 IP」(免費),申請完一定要把 PPPoE 帳號從 `xxxx@hinet.net` 改成 `xxxx@ip.hinet.net`,帳號沒改的話申請了不會生效
- 向電信業者申請固定 IP(通常要加錢)
- 租一台有公網 IP 的小 VPS 當中繼,由家裡主動連出去
3-2 埠號對不對
- RouterOS 的 WireGuard 預設埠是 13231,不是 51820。建立介面時沒寫 `listen-port=51820` 的話它就聽在 13231,而你轉發的是 51820 —— 封包送到一個沒人在聽的埠,安靜地被丟掉。用 `/interface/wireguard/print` 看實際的 `listen-port`
- Docker 的話看 compose 裡的 ports 有沒有 `/udp`:要寫 `"51820:51820/udp"`。少了那四個字元會變成轉發 TCP,永遠不會通
3-3 路由器的埠轉發
到路由器管理頁確認那一筆:
- 通訊協定: UDP <- 不是 TCP,也不是 Both
- 外部連接埠: 51820
- 內部 IP: 192.168.88.20 <- 伺服器主機的內網 IP
- 內部連接埠: 51820
複製代碼
⚠ 最常見的隱形失敗:伺服器主機是用 DHCP 拿 IP 的,重開機之後拿到新位址,轉發就轉到空氣去了。症狀是「以前能連,現在連不上」,而且什麼設定都沒改過。
到路由器的 DHCP 設定裡把那台主機設成固定 IP(DHCP 保留)。
3-4 伺服器自己的防火牆有沒有擋
- # Linux(ufw)
- sudo ufw status
- # Linux(firewalld)
- sudo firewall-cmd --list-all
- # RouterOS
- /ip/firewall/filter/print where chain=input
複製代碼
你會看到一份規則清單。要找的是:有沒有一條允許 UDP 51820,而且排在「丟棄其他全部」之前。
RouterOS 特別容易踩到順序:防火牆是由上往下、第一個命中就結束,你的放行規則排在 `drop all not coming from LAN` 後面的話,等於完全沒加。用 `place-before` 把它插到那條 drop 之前。
---
步驟 4:封包到了但沒有交握,那一定是金鑰
到這一步表示路徑完全正常。WireGuard 收到一個它驗不過簽章的封包時,會一聲不響地丟掉 —— 不回應、不記錄、什麼都沒有。這是設計上刻意的(避免被掃描探測),也是它最難除錯的地方。
4-1 不要用看的,用算的
公鑰是由私鑰算出來的,所以可以驗證:
- # 在任何一台有 wg 指令的機器上
- echo "貼上用戶端設定檔裡的 PrivateKey" | wg pubkey
複製代碼
你會看到一串 44 個字元、結尾是 `=` 的公鑰:
- 9kLm2XpQwErTyUiOp3AsDfGhJkL5ZxCvBnM8QwE=
複製代碼
|
|