先把零散規則整理成可更新的規則集
當規則只涵蓋少數網域時,直接寫在主設定的 rules 中很直覺;但隨著 GitHub、npm、Docker Hub 等服務各自增加網域,主設定就會逐漸變長。規則散落在不同位置,不容易看出哪一條屬於哪項服務,也難以單獨更新或回復。mihomo 的 rule-providers 可以把規則放在獨立檔案,再由主設定透過 RULE-SET 呼叫。
Provider 本身只負責取得與載入規則,不會決定流量要走哪個代理。實際的分流仍由 rules 中的順序與策略組決定;如果符合規則的連線要走 PROXY,設定中就必須存在名稱完全相同的代理或策略組。以下範例以 mihomo 為前提,示範由 GitHub Raw 提供 YAML 規則,再將三個服務分別交給現有的 PROXY 策略組。
分清提供者與引用規則
rule-providers 定義來源、快取路徑、更新間隔與規則行為;主設定的 rules 則用 RULE-SET,提供者名稱,策略組 引用它。兩邊名稱必須一致。以下的 github、npm 與 docker 是本例自行命名的提供者識別字,不是保留字。
先在 GitHub 建立並整理規則檔案
在自己的儲存庫建立一個規則目錄,例如 rules/,再分別新增 github.yaml、npm.yaml 與 docker.yaml。Provider 設為 behavior: domain 時,檔案內容使用包含 payload 的 YAML 結構,清單中的網域以網域規則語法表達。網域後綴規則會涵蓋該網域及其子網域;如只寫精確網域,則不會自動涵蓋其他子網域。
# rules/github.yaml
payload:
- DOMAIN-SUFFIX,github.com
- DOMAIN-SUFFIX,githubusercontent.com
- DOMAIN-SUFFIX,githubassets.com
- DOMAIN,raw.githubusercontent.com
GitHub 的網頁、下載資源與靜態資源可能使用不同網域。上面的項目是起始範例,不代表涵蓋 GitHub 的所有服務;啟用後應根據實際連線記錄補充必要網域,避免用過度寬泛的規則把無關服務一併分流。
# rules/npm.yaml
payload:
- DOMAIN-SUFFIX,npmjs.com
- DOMAIN-SUFFIX,npmjs.org
- DOMAIN,registry.npmjs.org
npm 網站、套件登錄服務與套件下載端點可能各自使用不同主機名稱。若套件管理工具仍有請求走到預設出站,請先檢查連線記錄中的實際目的網域,再把確實需要的網域加入這個檔案。不要因為某個套件的文件提到第三方 CDN,就直接把整個 CDN 網域加入規則。
# rules/docker.yaml
payload:
- DOMAIN-SUFFIX,docker.io
- DOMAIN-SUFFIX,docker.com
- DOMAIN-SUFFIX,dockerhub.com
- DOMAIN,registry-1.docker.io
- DOMAIN,auth.docker.io
Docker Hub 的映像檔傳輸可能經過額外的儲存或 CDN 主機,因此只列出上述網域仍可能不足。先以一次實際的映像檔拉取作測試,從核心連線記錄辨認失敗或走錯出站的主機,再採取最小幅度的補充。這樣比將某個大型雲端服務的整個網域後綴都交給代理更容易控制影響範圍。
在主設定加入 rule-providers 與分流順序
將下方設定中的 YOUR_NAME 換成自己的 GitHub 帳號或組織名稱,並把 YOUR_REPOSITORY 換成儲存庫名稱。URL 使用 GitHub Raw 的檔案網址;若使用分支名稱,該分支上的檔案更新會影響後續下載。path 是核心儲存下載內容的本機快取路徑,應讓每個 Provider 使用不同檔名。
rule-providers:
github:
type: http
behavior: domain
format: yaml
url: "https://raw.githubusercontent.com/YOUR_NAME/YOUR_REPOSITORY/main/rules/github.yaml"
path: ./ruleset/github.yaml
interval: 86400
npm:
type: http
behavior: domain
format: yaml
url: "https://raw.githubusercontent.com/YOUR_NAME/YOUR_REPOSITORY/main/rules/npm.yaml"
path: ./ruleset/npm.yaml
interval: 86400
docker:
type: http
behavior: domain
format: yaml
url: "https://raw.githubusercontent.com/YOUR_NAME/YOUR_REPOSITORY/main/rules/docker.yaml"
path: ./ruleset/docker.yaml
interval: 86400
rules:
- RULE-SET,github,PROXY
- RULE-SET,npm,PROXY
- RULE-SET,docker,PROXY
- GEOIP,LAN,DIRECT
- MATCH,PROXY
interval: 86400 表示以秒計算的更新間隔,也就是 24 小時。規則沒有頻繁變動時,每日更新通常足夠;若規則檔仍在頻繁調整,可暫時縮短間隔,穩定後再調回較長週期。Provider 的 path 是本機快取位置,不是 GitHub URL;修改檔案名稱時,URL 與本機路徑都要分別核對。
RULE-SET 的位置會影響結果。規則依序比對,命中後便採用該行指定的策略,不會繼續往下找。若在 Provider 前面已有涵蓋範圍較大的規則,例如將一整類網域送往 DIRECT,服務網域可能先被該規則攔截。應把需要優先處理的 Provider 放在會提前命中的寬泛規則之前,同時保留 LAN 等本機網路例外規則與最後的 MATCH。
如果你的代理策略組不叫 PROXY,請替換成設定中實際存在的名稱,例如 自動選擇。若不同服務需要不同出站,也可以將三行分別指定給不同策略組,但不要只改 Provider 名稱而忘記調整 RULE-SET 引用。修改後宜先備份原設定,再一次只調整一類規則,便於定位錯誤。
驗證載入結果並做好版本管理
先檢查 YAML 與遠端檔案
儲存後先檢查縮排與檔案內容。YAML 應使用空格縮排,不要混用 Tab;每個規則項目都應位於 payload 清單之下。再直接請求 Raw URL,確認回應是預期的 YAML,而不是 404 頁、登入頁或 HTML 錯誤內容。以下命令只展示檢查方式,請替換成自己的網址:
curl -L --fail --show-error \
"https://raw.githubusercontent.com/YOUR_NAME/YOUR_REPOSITORY/main/rules/github.yaml"
接著使用用戶端提供的設定檢查或核心測試功能載入主設定,並查看核心日誌。若日誌顯示 Provider 下載失敗,優先檢查網址、網路連線、回應狀態碼與檔案格式;若顯示解析錯誤,回到 YAML 檢查縮排、欄位名稱及規則語法。不同 mihomo 版本與用戶端的檢查入口可能不同,應以目前安裝版本提供的功能為準。
用實際連線確認分流
設定載入成功,只代表核心接受設定,不代表每條規則都命中了預期流量。分別開啟 GitHub 頁面、安裝一個 npm 套件、拉取一個 Docker Hub 映像檔,並在用戶端的連線頁面觀察目標網域、命中的規則與所選策略組。若出站不如預期,依序確認 Provider 是否載入、目的主機是否出現在清單、較前面的規則是否已先命中,以及目前策略組是否有可用節點。
- Provider 無法下載:核對 Raw URL、儲存庫可見性、檔案路徑及網路連線;私有儲存庫需要認證,而一般公開 Raw URL 不應假設能讀取私人內容。
- 設定載入成功但沒有命中:確認規則檔的
behavior與檔案格式相符,並檢查連線實際使用的網域是否已收錄。 - 命中 Provider 卻走錯策略:核對
RULE-SET第三個欄位,以及所指策略組是否存在、是否具備有效出站。 - 更新後行為改變:檢查遠端規則檔的差異與更新時間;必要時先回復到前一版,再分析新增或移除的項目。
使用固定版本降低變更風險
使用 main 分支網址很方便,但它會隨分支內容變動;若規則檔被誤改或儲存庫遭到不預期的變更,下一次更新也會帶入新內容。較容易追蹤的做法,是為規則變更建立明確的提交紀錄,檢查差異後再更新引用的版本。若想讓部署固定在某次提交,可將 Raw URL 中的分支名稱改為經審核的提交 SHA;規則有變更時,再有意識地更新該 SHA。
每次修改規則檔都應保留可辨識的提交訊息,例如「新增 GitHub 靜態資源網域」或「移除不再使用的 npm 網域」。發布前比對新增與刪除項目,並在自己的核心環境載入測試。還要注意,規則集通常不會像主設定一樣立即重新載入;變更後可能要等待更新間隔、透過用戶端更新規則,或重新載入設定,才能確認新內容已生效。