OpenWrt 旁路由執行 mihomo 核心:透明代理部署流程

整理在 OpenWrt 主路由或旁路由直接執行 mihomo 核心的部署流程,涵蓋核心檔案、設定目錄、透明代理轉送及區域網路裝置的閘道設定。

先釐清部署範圍:核心、閘道與透明代理是三回事

在 OpenWrt 上直接執行 mihomo,不代表安裝了有圖形介面的 Clash 用戶端。核心負責讀取設定、建立代理連線及執行規則;系統則負責將終端流量導入核心。啟動記錄正常,只能證明程序正在執行,無法證明區域網路裝置正在使用代理。

本文以 OpenWrt 23.05、24.10 常見的 firewall4 與 nftables 環境為基礎,採用 Linux TUN 搭配自動路由的部署方式。設定欄位是否可用,請以目前 mihomo 版本的設定檢查結果為準。舊版 firewall3、廠商客製化防火牆及既有代理外掛,不宜直接套用相同的流量接管規則。

  • 主路由部署:OpenWrt 原本就是終端的預設閘道,重點在於核心接管流量、防火牆放行及 DNS 轉送。
  • 旁路由部署:OpenWrt 與主路由位於同一個區域網路,還需要調整測試終端的閘道與 DNS。
  • 明確指定代理測試:由應用程式連線至 7890 混合連接埠,只用來初步確認節點與規則,不代表透明代理已設定完成。

規劃旁路由位址與終端閘道

先用一台終端進行驗證,不要立刻修改整個區域網路的 DHCP 發放設定。以下是一組完整的範例位址;實際部署時,應依照現有子網路一併調整,不要只修改其中一個位址。

裝置或參數範例值用途
區域網路子網路192.168.10.0/24主路由、旁路由與終端位於同一子網路
主路由192.168.10.1連線至網際網路,並繼續提供 DHCP
OpenWrt 旁路由192.168.10.2使用固定位址,避免與 DHCP 位址池衝突
旁路由預設閘道192.168.10.1核心連線至節點及直連目的地的上游閘道
測試終端192.168.10.100沿用原有子網路遮罩
終端閘道與 DNS192.168.10.2將測試終端的流量與 DNS 查詢交由旁路由處理

先在 LuCI 檢查「網路」→「介面」→「LAN」→「編輯」中的固定位址、IPv4 閘道與 DNS 設定。單網路埠旁路由通常透過 br-lan 連線至主路由;雙網路埠主路由則可能經由 PPPoE 或其他 WAN 裝置連外,請勿只憑網路卡名稱猜測出口。

ip -4 addr show
ip -4 route show
ip route get 223.5.5.5
cat /etc/resolv.conf

旁路由本身的預設路由應指向主路由,而不是指向自己。初次部署時,旁路由系統 DNS 請先使用可直接連線的 DNS 服務,避免發生「核心啟動時需要解析節點網域名稱,但 DNS 解析又依賴尚未啟動的核心」這類迴圈。

主路由只需保留一個 DHCP 服務。旁路由不要在同一個廣播網域再發放另一組位址。IPv6 也必須另外規劃:即使手動修改終端的 IPv4 閘道,終端仍可能透過主路由發出的 IPv6 路由公告直接連外。

放置 mihomo 核心與設定目錄

確認架構、核心模組與儲存空間

先確認 CPU 架構與韌體資訊,再選擇相符的 Linux 執行檔。x86_64、aarch64 與不同 MIPS 變體不可混用;部分發行套件還會區分指令集等級。檔名看起來相近,不代表能在同一台裝置上執行。

uname -m
ubus call system board
df -h /overlay /tmp
opkg list-installed | grep -E 'kmod-tun|firewall4|nftables'

使用 opkg 的官方韌體可透過 opkg update 和 opkg install kmod-tun 安裝 TUN 模組。模組必須與目前韌體核心相符;若相依性不符,應修正韌體與套件來源的對應關係,不要強制安裝其他核心版本的模組。自動接管所需的 nftables 功能,也取決於韌體的編譯選項。

固定執行檔路徑與工作目錄

將已解壓縮且符合裝置架構的核心上傳至 /usr/bin/mihomo,並將設定檔放在 /etc/mihomo/config.yaml。設定檔可能包含訂閱憑證,請勿讓一般使用者讀取目錄或檔案。若裝置的持久儲存空間不足,應先規劃外接儲存裝置,不要長期將正式設定放在重新啟動後會清空的 /tmp。

mkdir -p /etc/mihomo
chmod 700 /etc/mihomo
chmod 755 /usr/bin/mihomo
chmod 600 /etc/mihomo/config.yaml
/usr/bin/mihomo -v
/usr/bin/mihomo -t -d /etc/mihomo -f /etc/mihomo/config.yaml

-d 用來指定工作目錄,-f 用來指定設定檔,-t 則只會檢查設定。若設定引用 GeoIP、GeoSite、規則集或代理提供者檔案,也要檢查對應路徑、讀取權限及更新網路。初次排查時可先移除這些外部相依項目,避免將下載失敗誤判為 TUN 故障。

先驗證明確指定代理,再啟用 TUN 接管

建議分兩次啟動。第一次使用實際可用的節點設定,將 tun.enable 設為 false,再透過混合連接埠測試路由器本機連線。第二次確認節點可用後,再啟用 TUN 與自動路由。如此可分別排查節點問題與流量轉送問題。

以下提供最精簡的設定結構,用來檢查設定與直連基準。這份設定沒有代理節點,策略群組也只有 DIRECT,因此不會產生代理出口。正式使用時,請合併訂閱中的有效節點或 proxy-providers,並將實際節點加入策略群組;不要直接覆蓋既有的完整設定。

mixed-port: 7890
allow-lan: false
bind-address: 127.0.0.1
mode: rule
log-level: info
ipv6: false

tun:
  enable: false
  device: mihomo
  stack: mixed
  auto-route: true
  auto-redirect: true
  auto-detect-interface: true
  dns-hijack:
    - any:53

dns:
  enable: true
  listen: 127.0.0.1:1053
  ipv6: false
  enhanced-mode: fake-ip
  fake-ip-range: 198.18.0.1/16
  default-nameserver:
    - 223.5.5.5
  nameserver:
    - 223.5.5.5
    - 119.29.29.29

proxies: []

proxy-groups:
  - name: 出口選擇
    type: select
    proxies:
      - DIRECT

rules:
  - IP-CIDR,192.168.10.0/24,DIRECT,no-resolve
  - IP-CIDR,127.0.0.0/8,DIRECT,no-resolve
  - MATCH,出口選擇

先在前景執行 /usr/bin/mihomo -d /etc/mihomo -f /etc/mihomo/config.yaml,並透過另一個 SSH 工作階段觀察連接埠。若韌體已安裝 curl,可執行下方的請求;這個指令只會測試路由器本機至混合連接埠的連線,不會檢查區域網路的透明轉送。

curl --proxy http://127.0.0.1:7890 --connect-timeout 10 --max-time 20 -I https://example.com/

匯入實際節點後,確認「出口選擇」不再停留在 DIRECT,並參考記錄中的匹配規則、策略群組與節點名稱判斷請求路徑。只看網頁能否開啟,無法分辨是直連成功還是代理成功。

串接 TUN、策略路由與 OpenWrt 防火牆

明確指定代理測試通過後,將 tun.enable 改為 true,重新檢查設定並啟動。auto-route 會建立接管流量所需的路由;Linux 下的 auto-redirect 則會使用 nftables 等機制協助重新導向流量。自動產生的路由表編號、規則優先順序與鏈名稱可能隨版本改變,不要將網路上的某組固定編號當成通用標準。

ip link show mihomo
ip rule show
ip route show table all
nft list ruleset
sysctl net.ipv4.ip_forward

確認三項系統條件

  1. TUN 裝置已建立:應能看到設定中指定的 mihomo 裝置。若未出現,請先檢查 /dev/net/tun、模組與啟動權限。
  2. 路由接管已生效:比較啟動前後的 ip rule、路由表與 nftables 規則。核心記錄不應持續出現建立介面或新增規則失敗的訊息。
  3. 轉送未遭防火牆封鎖:必須啟用 IPv4 轉送,並允許 LAN 至 TUN 的轉送路徑。看到 TUN 介面,不代表 firewall4 已允許轉送。

在 LuCI 的「網路」→「防火牆」→「一般設定」檢查區域與轉送設定。若使用獨立的 TUN 區域,可依實際介面將 mihomo 裝置加入該區域,並允許 LAN 轉送至該區域;區域的輸入權限與轉送權限是兩回事。請勿為了測試而直接將 WAN 輸入政策改為接受。

不同韌體對非受管理裝置的區域綁定方式、自動重新導向與 firewall4 的整合方式各有差異,因此必須依據目前的規則集判斷,不宜直接複製固定的 iptables 指令碼。尤其不要同時新增 REDIRECT、TPROXY 與自動 TUN 三套接管規則;本文採用的是 TUN 方案。

單網路埠旁路由還要留意同介面轉送、回程路徑與連線追蹤。部分直連流量可能從 br-lan 進入後,又經由同一介面轉送給主路由。若出現只能單向連線或連線時斷時續,請先擷取封包確認來源位址與回程路徑,再判斷是否需要針對性來源位址轉換;不要一開始就對整個 LAN 開啟偽裝。

初次排查時,建議在「網路」→「防火牆」暫時停用軟體流量卸載與硬體流量卸載。等連線穩定後,再逐項恢復並重新測試。若旁路由可以上網、終端卻無法上網,請優先檢查轉送路徑,不要先更換節點。

設定 DNS 轉送,避免解析迴圈與 IPv6 繞過

範例中的 DNS 流程如下:終端連線至旁路由的 53 連接埠,由 dnsmasq 轉送至本機 mihomo 的 1053 連接埠,再送往上游 DNS 解析器。分開使用連接埠後,dnsmasq 與 mihomo 就不會爭用同一個監聽位址。

在 LuCI 的「網路」→「DHCP/DNS」→「一般設定」中,將 DNS 轉送目標設為 127.0.0.1#1053;再到對應的進階設定,檢查「不使用上游提供的 DNS 伺服器」選項。介面標籤可能因 LuCI 版本而異,重點是不要讓 dnsmasq 同時將請求轉送至其他自動取得的上游 DNS。

# 請先備份,以下操作會修改第一個 dnsmasq 執行個體
cp /etc/config/dhcp /etc/config/dhcp.before-mihomo
uci set dhcp.@dnsmasq[0].noresolv='1'
uci -q delete dhcp.@dnsmasq[0].server
uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#1053'
uci commit dhcp
/etc/init.d/dnsmasq restart

nslookup example.com 127.0.0.1

這組指令會取代該執行個體現有的 DNS 轉送清單。若原本設定了企業內部網域的條件式轉送,請先記錄並保留相關項目;若有多個 dnsmasq 執行個體,也不能直接假設第一個就是 LAN 使用的執行個體。還要確認終端的 DNS 位址確實是 192.168.10.2。

分辨一般 DNS、fake-ip 與加密 DNS

  • fake-ip:使用此模式時,查詢結果可能是 198.18.0.0/16 範圍內的位址。這是虛擬對應位址,不是目標網站的實際公網位址;後續連線仍須由核心接管。
  • 一般 DNS 劫持:any:53 用來接管相應的一般 DNS 請求,不代表能辨識並重新導向所有 DNS 協定。
  • DoH 與 DoT:瀏覽器的安全 DNS、應用程式內建的 DoH,以及使用 TCP 853 的 DoT,不會因為設定了一般 53 連接埠劫持,就自動改由 dnsmasq 處理。測試前請先確認應用程式實際使用的 DNS 路徑。
  • 上游 DNS 選擇:範例使用一般 IP 位址作為上游,是為了縮短啟動時的相依流程,並未啟用加密 DNS。若改用網域名稱形式的 DoH 位址,請另外規劃引導解析與節點網域名稱解析。

ipv6: false 只會限制核心對應的行為,不會停用終端收到的 IPv6 預設路由。初次驗證時可暫時關閉測試終端的 IPv6,之後再規劃 IPv6 TUN、路由公告與防火牆設定。不要因為 IPv4 出口正確,就認定雙堆疊流量都已接管。

透過 procd 管理啟動與重新啟動

確認前景執行、DNS 與終端連線都正常後,再註冊開機服務。以下 procd 指令碼只負責監控程序,不包含訂閱更新或自訂防火牆邏輯。請儲存為 /etc/init.d/mihomo,並確認沒有同名的其他外掛服務同時存在。

#!/bin/sh /etc/rc.common

START=99
STOP=10
USE_PROCD=1

start_service() {
    /usr/bin/mihomo -t -d /etc/mihomo \
        -f /etc/mihomo/config.yaml || return 1

    procd_open_instance
    procd_set_param command /usr/bin/mihomo \
        -d /etc/mihomo -f /etc/mihomo/config.yaml
    procd_set_param respawn 3600 5 5
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_set_param file /etc/mihomo/config.yaml
    procd_close_instance
}
chmod 755 /etc/init.d/mihomo
/etc/init.d/mihomo enable
/etc/init.d/mihomo start
logread -e mihomo

啟動服務前,先結束原本在前景執行的核心,避免兩個執行個體爭用連接埠與 TUN 裝置。此指令碼預設以 root 身分執行,因為建立 TUN、設定路由與防火牆需要相應權限;因此也必須嚴格控管設定檔、訂閱來源與核心檔案。

修改設定後,先執行 mihomo -t,再執行 /etc/init.d/mihomo restart。指令碼中的檔案宣告不代表具備自動更新訂閱的功能;更新訂閱仍須另外安排下載、設定檢查與原子替換。設定含有憑證時,也不要將完整啟動記錄公開。

開機順序較晚,不代表網路已可使用。務必完整重新啟動一次,確認介面上線後能否解析節點網域名稱、建立連線並恢復終端連線。依賴遠端規則集的部署,也要考慮冷開機時外部檔案可能暫時無法取得。

依連線路徑逐步驗收,並保留回復方式

驗收應從路由器本機開始,再逐步測試單一終端,最後才擴大至 DHCP 發放設定。每次只變更一個項目,並記錄相應的系統記錄與閘道設定。測速結果只能反映當下的傳輸狀況,不能取代路由與 DNS 路徑檢查。

現象優先檢查項目判斷依據
核心無法啟動架構、設定、連接埠、TUN 模組查看設定檢查結果與啟動錯誤,先不要修改終端閘道
明確指定代理正常,終端連線失敗終端閘道、TUN 接管、LAN 轉送確認終端請求是否出現在核心記錄中
IP 位址可連線,網域名稱無法存取dnsmasq、1053 監聽狀態、上游 DNS 解析分別測試旁路由與終端的 DNS 查詢
部分應用程式仍然直連規則、IPv6、應用程式內建 DNS核對實際套用的策略與雙堆疊出口
重新載入防火牆後連線中斷確認自動產生的規則是否仍存在比較重新載入前後的 nftables 與策略路由
重新啟動後無法恢復服務啟用狀態、介面啟動時序、冷開機相依項目從系統記錄找出第一個失敗點

單一終端測試通過後,再擴大部署

  1. 先讓終端連線至主路由與旁路由的管理位址,確認區域網路直連正常。
  2. 確認終端的 IPv4 預設閘道與 DNS 都指向旁路由,清除舊的 DNS 快取,再建立新的瀏覽器連線。
  3. 分別測試應直連與應走代理的請求,查看對應規則與節點,不要只看網頁是否載入。
  4. 確認 UDP 應用程式、IPv6 策略及防火牆重新載入後的狀況,再調整主 DHCP 服務發放的閘道與 DNS。

正常停止後,檢查 TUN 介面、策略路由及自動產生的防火牆規則是否已清除。若仍有殘留,請依據先前保存的基準設定還原;不要透過遠端指令清空整個 nftables 規則集。若需要清除執行狀態,可先還原持久設定,再安排重新啟動。

OpenWrt 旁路由部署的重點不只是將執行檔放進路由器,而是要把終端閘道、DNS、流量接管、規則出口與服務生命週期串成一條可驗證的路徑。依序完成檢查,日後更換訂閱、調整分流或升級核心時,才能明確找出問題所在的層級。

下載 Clash 安裝檔與系統需求