先区分整份订阅与节点 Provider
订阅更新失败,先看是谁在下载、下载的是什么。图形客户端的订阅更新和 mihomo 的 proxy-providers 是两条不同链路:前者通常导入整份配置,后者只刷新节点集合。节点能连接,不代表订阅地址此刻还能访问;订阅下载成功,也不代表里面的节点都可用。
- 客户端订阅:可能包含
dns、proxy-groups、rules等完整配置。更新频率由客户端管理,界面中的自动更新设置不等于内核 Provider 的定时器。 - 节点 Provider:由 mihomo 在运行时读取。远程内容应采用它支持的节点集合格式,本文使用顶层
proxies:的 YAML;策略组通过use引用它。 - 健康检查:向测试地址发起请求,检查节点的可达性与延迟。它不负责重新下载订阅,也不能修复过期的订阅凭据。
按报错定位:先 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 '订阅 URL: ' 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 应换成订阅 URL 的主机名,只保留域名,不带协议和令牌。--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
证书错误、UA 被拒与格式不兼容
证书错误:先校时,不跳过验证
先执行 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 为准,不要修改一个没有被读取的同名文件。
- 备份现有配置,保留可以恢复的版本。
- 将 Provider 与策略组一起写入主配置,确认
use与 Provider 名字完全一致。 - 建立缓存目录,确保运行内核的用户具有写权限。
- 运行配置检查;通过后才重启服务。
- 查看启动与后续更新日志,确认没有下载、解析或权限错误。
下面假定工作目录为 ~/.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 引用 → 定时更新 → 节点检查。这样能把“订阅拿不到”和“节点不能用”分开,避免反复重装客户端却没有触及故障点。首次部署可先按快速上手完成最小配置,再逐项加入自动刷新设置。