如何利用 Cloudflare WARP 解決 GitHub 下載太慢的問題
家裡 HiNet 連 GitHub 常常很慢。這篇用 wgcf 產生 WARP 的 WireGuard 設定,在 RouterOS v7 上只讓 GitHub 的流量走 WARP,其他照舊走 HiNet,並附上可重跑、可復原的完整設定。
家裡的網路是 HiNet,唯獨連 GitHub 常常很慢。網頁還勉強能開,但只要碰到 raw.githubusercontent.com、release 檔案這類下載,就很容易卡住。
同樣的東西,開手機熱點或掛上 Cloudflare WARP 就順了。既然 WARP 會快,就讓路由器只把 GitHub 的流量送進 WARP,其他流量完全不動。今天實際部署成功,順手整理成這篇。
之前也寫過一篇用 RouterOS 處理 X 影片轉圈圈的:如何改善網路品質 - X/推特 影片。
這篇是同一台路由器的另一個問題。
環境
- 路由器:MikroTik RB450Gx4
- 系統:RouterOS 7.24.2
- WAN:HiNet PPPoE,介面名稱
pppoe-dynamic-out - LAN:interface list 叫
LAN
要 v7 才有內建 WireGuard,v6 用不了。
思路
- 目的地是 GitHub 的連線,走 WARP。
- 其他連線,照舊走 HiNet。
- WARP 掛了,GitHub 的連線自動退回 HiNet。
這就是 policy-based routing,依照連線的目的地決定走哪一張路由表:
flowchart LR
C["LAN 用戶端"] --> M{"mangle prerouting<br/>目的地在 warp-gh 清單?"}
M -->|"否"| MAIN["main 路由表"]
MAIN --> WAN["pppoe-dynamic-out<br/>HiNet"]
M -->|"是:mark-connection<br/>再 mark-routing"| T["路由表 via-warp"]
T -->|"distance=1(primary)"| WG["wg-warp<br/>WireGuard"]
T -.->|"distance=2<br/>WARP 掛掉時"| WAN
WG --> CF["Cloudflare WARP"]
CF --> GH["GitHub"]
WAN --> NET["其他網站"]
NW["netwatch<br/>ping 1.0.0.1"] -.->|"down 時停用 primary"| T準備:用 wgcf 拿到 WARP 的 WireGuard 設定
WARP 官方只有 App,路由器裝不了,但底層就是 WireGuard。wgcf 是非官方的開源工具,能註冊一台免費的 WARP 裝置,並匯出標準的 WireGuard profile。在電腦上跑一次就好:1
2wgcf register --accept-tos # 註冊裝置,產生 wgcf-account.toml
wgcf generate # 產生 wgcf-profile.conf
這兩個檔案都含私鑰,別放進 git,也別貼到任何地方。
RouterOS 設定逐段解說
以下依序逐段解說完整設定,數值取自 wgcf-profile.conf,私鑰用 <PRIVATE_KEY> 代替,位址與 endpoint 以你自己的為準。動手前先用 /system backup save 備份一份,弄壞了可以還原。
先清掉舊的,讓設定可以重跑
1 | /tool netwatch remove [find comment~"warp-gh"] |
這些指令建立的每個物件都帶 comment=warp-gh(primary 路由是 warp-gh:primary,所以用 ~ 比對)。開頭先全刪再重建,重跑就不會疊出重複規則。順序是先刪引用別人的,最後才刪介面與路由表。
WireGuard 介面
1 | /interface wireguard |
mtu=1280:wgcf 作者建議的值。WireGuard 要吃 header,外面又是 PPPoE 的 1492,設小一點比較不會被切或被丟。allowed-address=0.0.0.0/0:要轉送任意網站只能全開,哪些流量要進來交給後面的路由表決定。persistent-keepalive=25s:我們在 NAT 後面,定期送封包避免對應過期。
專用路由表與容錯
1 | /routing table |
via-warp 是獨立的路由表,有兩條預設路由:distance=1 走 wg-warp,平常用這條;distance=2 走 HiNet,primary 被停用時才接手。
WireGuard 是無連線的,對面掛了介面照樣是 running,RouterOS 不會發現。所以用 netwatch 每 10 秒 ping 一次 1.0.0.1,不通就停用 primary,恢復再打開。
探測目標必須固定走 WARP,所以那條 1.0.0.1/32 放在 main 表。如果探測跟著 via-warp 走,primary 一停用 ping 就改走 HiNet,永遠是 up,故障就偵測不到了。代價是 LAN 裡連 1.0.0.1 的流量也會走 WARP,WARP 掛掉時它就不通。家裡有設備把 DNS 設成 1.0.0.1 要留意,或把探測目標換成別的位址。
目的地清單:address-list
1 | /ip firewall address-list |
v7 的 address-list 可以直接填網域,路由器會自己解析,把 IP 以動態項目放進清單,TTL 到了再更新。這次 7 個網域解析出 17 筆 IP。
比對看的是 IP 不是網域,用戶端用自己的 DNS 或 DoH 拿到不同 IP 就抓不到,家裡設備都用路由器當 DNS 的話問題不大。
也可以把 Fastly 整個公開網段都丟進清單,不怕 DNS 不一致。但 Reddit、PyPI 等一大票網站也在 Fastly 上,會被一起送進 WARP,我只想動 GitHub,所以我用 fqdn 模式。
mangle:先標連線,再標路由
1 | /ip firewall mangle |
這是分流的核心。
- 第一條只看新連線:從 LAN 進來、目的地在
warp-gh清單的,在連線上貼warp-gh標籤,之後同一條連線不用再比對清單。 - 第二條把帶標籤連線的封包標上 routing mark
via-warp,路由決策就改查那張表。必須放prerouting,因為 routing mark 要在路由決策之前貼;in-interface-list=LAN讓路由器自己的流量不受影響。 - 第三條是 MSS clamp。
wg-warp的 MTU 只有 1280,把 SYN 的 MSS 改成配合 path MTU,避免網頁開得了、大檔案卻卡住。 - masquerade:WARP 只認 wgcf 分配的
172.16.0.2,LAN 私有 IP 送過去不會被理,出 tunnel 要把來源換掉。
FastTrack:被標記的連線不能走捷徑
1 | /ip firewall filter |
預設的 FastTrack 規則會讓已建立的連線跳過 mangle,mark-routing 就失效,連線跑到一半又回到 main 表走 HiNet。所以加上 connection-mark=no-mark:沒標記的照樣加速,warp-gh 的連線不加速。GitHub 流量不大,對 RB450Gx4 沒什麼負擔。
這行改的是既有規則,沒有 warp-gh comment,所以復原時不會被移除,留著也不影響其他流量。
IPv6:直接拒絕,讓用戶端退回 IPv4
1 | /ipv6 firewall address-list |
HiNet 有給 IPv6,而上面的分流都是 IPv4,用戶端走 IPv6 連 GitHub 就會繞過整套設定。所以不做 IPv6 分流,直接對這些目的地的 IPv6 連線 reject,用戶端會立刻失敗、退回 IPv4,接著被 mangle 抓到。不需要這段可以不加。
驗證
1 | /interface wireguard peers print detail where comment="warp-gh" |
peer 的 last-handshake 有數值就代表 tunnel 通了,netwatch 要是 up。1
2/ip firewall address-list print where list=warp-gh
/ip firewall mangle print stats where comment="warp-gh"
我這邊 7 個網域解析出 17 筆 IP。抓幾個檔案之後,mark-connection 命中 3 個連線、mark-routing 命中 102 個封包,表示流量確實被導進 via-warp。
設定前後比對
分流靠的是 mangle 那條 mark-connection,停用它就等於回到 HiNet 直連,不用動其他設定:1
2
3
4# 停用:GitHub 流量走原本的 HiNet 直連
/ip firewall mangle disable [find comment="warp-gh" and action=mark-connection]
# 啟用:GitHub 流量走 WARP
/ip firewall mangle enable [find comment="warp-gh" and action=mark-connection]
規則只對新連線貼標籤,切換後要重新下載。測試方法:
- 同一台 Mac、同一條 HiNet PPPoE。
- 下載 GitHub release 檔
gh_2.102.0_macOS_arm64.zip(13.7 MB,github.com/cli/cli)。 - 每輪先停用規則量一次(HiNet 直連),再啟用量一次(WARP),交替 3 輪。
- curl 的
--max-time設 180 秒。
| 輪 | HiNet 直連 | WARP |
|---|---|---|
| 1 | 114.66 s,0.12 MB/s | 1.29 s,10.62 MB/s |
| 2 | 180 s 逾時未完成,約 0.06 MB/s | 1.60 s,8.55 MB/s |
| 3 | 180 s 逾時未完成,約 0.06 MB/s | 2.39 s,5.72 MB/s |
直連大約只有 0.06–0.12 MB/s,三輪裡有兩輪三分鐘內下載不完;走 WARP 是 5.7–10.6 MB/s,快了大概兩個數量級。這只是某個時段的結果,換個時間數字可能差很多,想知道自己家的情況,照上面切換規則量一次就好。
復原
所有物件都帶 warp-gh comment,用第一段那組 remove [find comment~"warp-gh"] 就能全部移除。FastTrack 那條是改既有規則,留著無害。真的弄壞了,還有動手前做的備份可以還原(/system backup load,會重新開機)。
踩坑與心得
- WAN 介面名稱別寫死:WAN 介面名稱每台不同,我原本以為是
pppoe-out1,實機卻叫pppoe-dynamic-out,那條distance=2路由的 gateway 要填自己的,名稱錯了這條路由就加不進去,WARP 掛掉時沒有退路。用 DHCP 或固定 IP 的人要填上游 gateway 的 IP。 - fqdn 模式不是萬能:GitHub 換新下載網域,或用戶端用別的 DNS,就會漏網。某個網站還是慢,先用
/ip firewall address-list print看它的 IP 在不在清單裡。