先釐清整份訂閱與節點 Provider 的差異

訂閱更新失敗時,先確認是哪個元件正在下載,以及下載的是什麼。圖形用戶端的訂閱更新與 mihomo 的 proxy-providers 是兩條不同的流程:前者通常會匯入整份設定,後者只會更新節點清單。節點能連線,不代表此刻仍能連上訂閱網址;訂閱下載成功,也不代表其中的節點都能使用。

  • 用戶端訂閱:可能包含 dns、proxy-groups、rules 等完整設定。更新頻率由用戶端管理,介面中的自動更新設定不等於核心 Provider 的定時器。
  • 節點 Provider:由 mihomo 在執行時讀取。遠端內容必須採用 mihomo 支援的節點清單格式,本文使用頂層 proxies: 的 YAML;策略組則透過 use 引用該 Provider。
  • 健康檢查:向測試網址發送請求,檢查節點是否可連線及其延遲。健康檢查不會重新下載訂閱,也無法修復已過期的訂閱憑證。

依錯誤訊息逐步排查:先查 HTTP,再查解析,最後檢查節點

先保留一次更新失敗時的記錄,記下時間、請求網域與錯誤訊息末尾。不要只截取介面上的「更新失敗」。如果記錄中包含訂閱網址的查詢參數,分享前請先遮蔽存取權杖。以下錯誤發生在不同階段,不適合用同一種方式處理。

記錄或狀態 優先檢查項目 接下來怎麼做
no such host 訂閱網域解析 執行 getent,確認網域名稱沒有拼錯
i/o timeout、context deadline exceeded 連線路徑、出口與逾時階段 分別測試直連與透過本機代理連線
x509: certificate has expired 本機時鐘與伺服器憑證有效期限 先校正時間,再檢查網站憑證
certificate signed by unknown authority 系統 CA 與企業 HTTPS 檢查 確認信任根憑證的來源
HTTP 401 / 403 存取權杖、存取政策與 User-Agent 查閱服務商說明並檢查回應內容
HTTP 429 請求頻率限制 依 Retry-After 指示等待,並拉長更新週期
yaml: unmarshal errors 回應格式、欄位型別與縮排 確認回傳內容是否為 HTML 或錯誤訊息

逾時不一定代表節點故障

訂閱網域可能只能透過特定網路連線,也可能在代理出口受到流量限制。Linux 終端機中的 HTTPS_PROXY 設定與桌面系統代理不一定相同,用戶端的更新程式也未必使用同一組設定。因此,即使「瀏覽器能開啟網站」,也不能證明背景訂閱請求走的是相同路徑。

以下指令會先讀取訂閱網址,避免將存取權杖直接寫入 shell 歷史記錄。回應會存放在權限受限的暫存目錄。指令不會自動跟隨重新導向,也不會輸出訂閱內容;若回應為 301 或 302,請先在本機檢查重新導向目標,確認來源可信後再連線。

umask 077
workdir=$(mktemp -d)
read -r -s -p '訂閱網址:' SUB_URL
printf '\n'

curl --noproxy '*' --connect-timeout 10 --max-time 30 \
  -sS -D "$workdir/headers.txt" \
  -o "$workdir/body.txt" \
  -w 'HTTP=%{http_code} total=%{time_total}s\n' \
  "$SUB_URL"

getent ahosts example.com

最後一行的 example.com 請改成訂閱網址的主機名稱,只填網域,不要包含通訊協定或存取權杖。--noproxy '*' 用來停用 curl 明確設定的代理;若系統啟用了 TUN 或路由器透明代理,流量仍可能被接管,因此不能據此證明流量是實體直連。

確認核心監聽的 mixed-port 確實為 7890 後,可透過明確指定 HTTP 代理的請求進行比較。以下指令會沿用上一步的變數;結果只代表這次請求的實際狀態,不預設一定成功。

curl --noproxy '' --proxy http://127.0.0.1:7890 \
  --connect-timeout 10 --max-time 30 \
  -sS -D "$workdir/proxy-headers.txt" \
  -o "$workdir/proxy-body.txt" \
  -w 'HTTP=%{http_code} total=%{time_total}s\n' \
  "$SUB_URL"

# 在本機檢查完成後,刪除含有訂閱資訊的暫存檔
unset SUB_URL
rm -rf -- "$workdir"
unset workdir

憑證錯誤、User-Agent 遭拒與格式不相容

憑證錯誤:先校正時間,不要略過驗證

先執行 timedatectl status,確認日期、時區與時間同步狀態。憑證有效期限是依絕對時間判定,顯示的時區不同本身不會造成憑證過期。確認時鐘正確後,再檢查系統 CA 憑證套件是否已安裝、企業網路是否替換了 HTTPS 憑證,以及訂閱服務的憑證是否已過期。

Debian、Ubuntu 可檢查 ca-certificates 套件;若管理員提供企業根憑證,請依照發行版的程序安裝,並確認憑證來源。不要長期使用 curl -k 或略過憑證驗證。訂閱內容含有連線憑證,驗證失效會增加內容遭竄改的風險。

401、403:先檢查憑證,再處理 User-Agent

401 常見原因是存取權杖失效;403 也可能與方案狀態、IP 限制、User-Agent 政策或防護頁面有關。請以服務商的回應為準,不要看到 403 就不斷更換 UA。即使瀏覽器收到 HTTP 200,也可能只取得登入頁面,而不是有效的訂閱內容。

若服務商明確要求 mihomo 使用特定 User-Agent,可在 Provider 中設定請求標頭。header 的每個值都必須使用字串清單。以下為欄位寫法,請放入對應的 HTTP Provider;這不能取代帳戶授權,也不應用來規避存取控制。

header:
  User-Agent:
    - mihomo

解析失敗:檢查回應內容結構,不只看副檔名

訂閱網址以 .yaml 結尾,不代表伺服器回傳的內容就是 YAML。請在本機檢查回應標頭和內容開頭:HTML 防護頁面、JSON 錯誤訊息、Base64 節點清單、完整設定與 Provider 節點清單,都是不同的資料格式。HTTP 200 只代表請求層級成功。

本文使用的 Provider 回應內容應具備以下頂層結構。範例不含真實節點,proxies: [] 僅用來說明欄位型別;實際服務必須提供非空的節點清單。不要將整份設定直接當成節點 Provider,也不要預期其中的 rules 會自動合併到主要設定。

proxies: []
  • 主要設定中的 Provider 名稱必須唯一,建議使用固定的英文名稱,例如 airport。
  • YAML 請使用空格縮排,不要使用 Tab。建議將 URL 加上引號,避免特殊字元造成歧義。
  • 請在可信任的環境中轉換節點格式,不要將含有存取權杖的訂閱交給來源不明的轉換網站。

proxy-providers 定時更新:完整欄位與引用關係

以下設定用來說明各欄位的關係:每隔 3600 秒下載一次節點清單,每隔 600 秒執行一次健康檢查。策略組 PROXY 透過 use: [airport] 引用節點;最後一條規則會將未符合其他規則的流量交由該組處理。這不是可直接使用的訂閱;example.com 是文件範例網域,使用前必須改成服務商提供的 Provider 網址。

mixed-port: 7890
allow-lan: false
mode: rule
log-level: info

proxy-providers:
  airport:
    type: http
    url: "https://example.com/subscription.yaml"
    path: ./providers/airport.yaml
    interval: 3600
    health-check:
      enable: true
      url: "https://www.gstatic.com/generate_204"
      interval: 600
      timeout: 5000
      lazy: true

proxy-groups:
  - name: PROXY
    type: select
    use:
      - airport

rules:
  - MATCH,PROXY
欄位 範例值 用途與單位
interval 3600 遠端 Provider 更新週期,單位為秒
path ./providers/airport.yaml 相對於核心工作目錄的本機快取路徑
health-check.interval 600 節點健康檢查週期,單位為秒
health-check.timeout 5000 單次檢查逾時時間,單位為毫秒
health-check.lazy true 未使用時可略過定時檢查,減少探測次數

health-check.url 應指向能穩定回傳預期回應的輕量網址。以上 URL 只是常見範例,不保證所有出口都能連線。若測試網址故障,許多正常節點可能會同時顯示異常;此時應先排除探測目標的問題,而非批次刪除節點。

更新請求會經由哪個出口

目前 mihomo 的 HTTP Provider 可透過 proxy 欄位指定下載時使用的代理或策略組。若未指定,不要假設它一定會沿用桌面系統代理。若訂閱必須透過代理才能連線,請先確認指定的出口能在首次下載訂閱前獨立連線。

更新週期不宜設得太短。3600 秒等於 1 小時,通常比每分鐘輪詢更合適;實際設定仍應遵守服務商的限制。每次健康檢查可能會測試多個節點,節點越多,請求總量就越大。單純縮短檢查間隔,不會讓訂閱更新得更快。

套用設定:驗證、權限與重新啟動順序

先確認目前的執行方式。圖形用戶端產生的執行設定,可能在下次切換訂閱時覆蓋手動修改;請使用用戶端支援的持久化合併機制。若獨立執行 mihomo,則以實際啟動參數中的 -d 和 -f 為準,不要修改未被載入的同名檔案。

  1. 先備份現有設定,保留可供還原的版本。
  2. 將 Provider 與策略組一併加入主要設定,確認 use 中的名稱與 Provider 名稱完全相同。
  3. 建立快取目錄,並確認執行核心的使用者具有寫入權限。
  4. 先執行設定檢查,確認通過後再重新啟動服務。
  5. 檢查啟動及後續更新記錄,確認沒有下載、解析或權限錯誤。

以下假設工作目錄為 ~/.config/mihomo、設定檔為 config.yaml,且已建立名為 mihomo.service 的 systemd 使用者服務。若使用系統層級的服務,請依實際部署調整設定目錄與指令中的使用者範圍。

cp ~/.config/mihomo/config.yaml \
  ~/.config/mihomo/config.yaml.bak
mkdir -p ~/.config/mihomo/providers
chmod 700 ~/.config/mihomo/providers
chmod 600 ~/.config/mihomo/config.yaml

mihomo -t -d ~/.config/mihomo \
  -f ~/.config/mihomo/config.yaml

# 僅在檢查通過後執行
systemctl --user restart mihomo.service
journalctl --user -u mihomo.service -n 100 --no-pager

mihomo -t 可用來檢查設定,但無法單獨證明所有遠端內容與節點都能正常運作。若設定檢查通過但更新仍失敗,請繼續查看實際執行記錄。若服務回報 permission denied,請檢查目錄擁有者、服務使用者與快取路徑;不要直接開放整個設定目錄,讓所有使用者都能寫入。

若 Provider 快取仍存在,更新失敗後可能繼續使用舊節點。介面顯示「仍有節點」不代表更新成功。可對照記錄並執行 stat ~/.config/mihomo/providers/airport.yaml 查看快取狀態;修改時間只能做為輔助線索,無法單獨證明遠端內容已變更。

常見問題:為什麼自動更新看起來沒有生效?

設定 interval 後,關閉用戶端還會繼續更新嗎?

不會。這段 YAML 不會自動喚醒已關閉的核心。Provider 定時更新必須仰賴 mihomo 持續執行;電腦進入休眠、服務停止或網路中斷都會影響更新。若要在 Linux 上長時間執行,請依部署方式設定 systemd;服務成功啟動一次,不代表已設定開機自動啟動。

訂閱已更新,為什麼規則和 DNS 沒有變化?

proxy-providers 更新的是節點清單,不是整份主要設定。規則可另外使用 rule-providers 提供,但也必須在 rules 中引用規則集。若要替換整份設定,請使用用戶端的訂閱更新流程,並確認本機覆寫規則的優先順序。欄位關係可參閱設定參考。

健康檢查成功,為什麼特定網站還是無法開啟?

健康檢查只會測試指定目標,無法涵蓋所有網站。特定網站也可能受到 DNS 解析、規則匹配、出口地區或目標服務限制影響。請先確認實際命中的策略組與節點,再針對目標網域排查。一次探測成功,不代表整條連線路徑都沒有問題。

如何確認問題已經排除?

  • 訂閱請求回傳的是有效內容,而非登入頁面或錯誤訊息。
  • 執行記錄沒有 Provider 解析錯誤,策略組也能顯示預期的節點。
  • 首次啟動時不依賴舊快取,也能成功下載訂閱。
  • 等待一個設定週期後,再確認是否有後續更新。
  • 重新啟動用戶端後設定仍然保留,存取權杖與節點憑證也沒有出現在公開記錄中。

依序排查:下載連線 → HTTP 狀態 → 內容格式 → Provider 引用 → 定時更新 → 節點檢查。這樣可區分「無法取得訂閱」與「節點無法使用」,避免反覆重裝用戶端卻沒有找出問題所在。首次部署可先依照快速入門完成基本設定,再逐步加入自動更新功能。