430 lines
14 KiB
Markdown
Executable File
430 lines
14 KiB
Markdown
Executable File
# NAS媒体刮削TMDB接口访问问题完整排查\+落地文档
|
||
|
||
# NAS 媒体刮削 TMDB 接口访问问题完整排查 \+ 落地文档
|
||
|
||
> 文档来源:本次全部对话记录整理,包含:故障现象、完整排错过程、根因分析、两套可落地解决方案、配置模板、验证命令、故障清单
|
||
> 环境:MacOS Clash Verge Rev、群晖 NAS(Mihomo\+Hysteria2 正常)、飞牛 fnOS(Docker 部署 MoviePilot、tinyMediaManager)
|
||
>
|
||
>
|
||
|
||
## 目录
|
||
|
||
1. 故障现象汇总
|
||
|
||
2. 前期网络排错全过程(curl、TLS、Hysteria2 排查)
|
||
|
||
3. 根因分析
|
||
|
||
4. 方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理
|
||
|
||
5. 方案二【备用兜底方案】Cloudflare Worker TMDB 中转(鉴权 \+ 缓存,无需代理)
|
||
|
||
6. 两套方案切换规则
|
||
|
||
7. 统一故障排查清单
|
||
|
||
8. 附录:测试命令、参考脚本
|
||
|
||
---
|
||
|
||
# 1\. 故障现象汇总
|
||
|
||
## 1\.1 网络侧现象
|
||
|
||
1. MacOS 客户端:Clash Verge Rev(Mihomo 内核),Hysteria2 节点,访问`api.themoviedb.org`正常,TMDB 接口可访问。
|
||
|
||
2. 群晖 NAS:部署 Mihomo,**同一份 config\.yaml、相同内核版本**,Hysteria2 节点正常,MoviePilot、TinyMediaManager 媒体刮削,TMDB 接口调用全部正常。
|
||
|
||
3. 飞牛 fnOS:
|
||
|
||
- 飞牛系统无系统级全局代理;
|
||
|
||
- 飞牛 Docker 内部署 Mihomo,订阅同样 Hysteria2 节点,节点列表加载成功,但所有 Hysteria2 节点 TLS 握手失败,`SSL_ERROR_SYSCALL`;
|
||
|
||
- 在飞牛上部署 MoviePilot、tinyMediaManager,调用 TMDB API 接口全部超时失败,无法刮削媒体元数据。
|
||
|
||
> 测试现象:curl 访问`https://api.themoviedb.org`,TLS 握手卡在 Client Hello 后直接断开,报错:`curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL`。
|
||
>
|
||
>
|
||
|
||
## 1\.2 测试过程关键现象
|
||
|
||
1. 裸网直接访问`api.themoviedb.org:443`:TCP 能建立连接,TLS 握手中断,SNI 被网络拦截。
|
||
|
||
2. 使用本地 SOCKS5 代理(7890),未使用`--socks5-hostname`:本地解析域名,拿到污染 IP,握手失败;使用`--socks5-hostname`,域名交由代理远端解析。
|
||
|
||
3. Hysteria2 依赖 UDP QUIC 协议;飞牛 fnOS 的 OVS 虚拟交换机 \+ 家庭路由器会拦截 UDP 出站,导致 HY2 QUIC 握手超时。
|
||
|
||
4. 飞牛 Docker 容器**不会自动继承宿主机的代理**,容器内程序(MoviePilot/TMM)不会自动走宿主机 Mihomo。
|
||
|
||
---
|
||
|
||
# 2\. 前期网络排错全过程记录
|
||
|
||
## 2\.1 基础 curl 裸网测试
|
||
|
||
```bash
|
||
# 测试80端口HTTP
|
||
curl -v api.themoviedb.org
|
||
# HTTPS裸网测试,TLS握手失败
|
||
curl -v https://api.themoviedb.org
|
||
```
|
||
|
||
现象:TCP 连接成功,发送 TLS Client Hello 之后直接断开,报错 `SSL_ERROR_SYSCALL`。
|
||
|
||
> 尝试指定 TLS 版本`--tls-max 1.2`,依旧握手失败。
|
||
>
|
||
>
|
||
|
||
## 2\.2 SOCKS 代理测试(本地 7890 端口)
|
||
|
||
```bash
|
||
# 错误:本地解析域名
|
||
curl -v --socks5 127.0.0.1:7890 https://api.themoviedb.org
|
||
# 正确:远端域名解析(socks5h)
|
||
curl -v --socks5-hostname 127.0.0.1:7890 https://api.themoviedb.org
|
||
# 验证代理出口IP
|
||
curl -v --socks5-hostname 127.0.0.1:7890 https://ifconfig.me
|
||
```
|
||
|
||
> 结论:`--socks5` 是本地解析域名,容易拿到污染 IP;**`--socks5-hostname`** 将域名解析交给远端代理服务器,规避 DNS 污染。
|
||
>
|
||
>
|
||
|
||
## 2\.3 协议选型评估:mieru /anytls/hysteria2
|
||
|
||
|协议|特点|本次环境适配性|
|
||
|---|---|---|
|
||
|Hysteria2|QUIC/UDP,速度好;**强依赖 UDP 出站**|Mac / 群晖正常;飞牛 fnOS 受 OVS、路由器 UDP 拦截,无法稳定运行|
|
||
|AnyTLS|TCP 隧道,不依赖 UDP;存在内层 TLS1\.3 报文被篡改风险|UDP 不通场景备选,稳定性弱于 HY2|
|
||
|Mieru|TCP 隧道,抗干扰;同样 TCP 底层,TLS1\.3 握手存在概率异常|备选|
|
||
|
||
> 结论:飞牛环境不适合本地部署 Hysteria2,放弃在飞牛本机跑代理。
|
||
>
|
||
>
|
||
|
||
## 2\.4 Mihomo 日志排查方法(飞牛 Docker)
|
||
|
||
1. 修改 Mihomo 配置,开启 debug 日志
|
||
|
||
```yaml
|
||
log-level: debug
|
||
external-controller: 127.0.0.1:9090
|
||
```
|
||
|
||
2. 查看容器实时日志
|
||
|
||
```bash
|
||
# 查看容器名
|
||
docker ps | grep mihomo
|
||
# 实时跟踪日志
|
||
docker logs -f --tail 100 mihomo
|
||
# 导出日志到文件
|
||
docker logs mihomo > mihomo-debug.log
|
||
```
|
||
|
||
3. 关键词识别
|
||
|
||
- `quic: connection timed out` → UDP 出站被拦截(本次核心问题)
|
||
|
||
- `unsupported proxy type: hysteria2` → Mihomo 内核版本过低
|
||
|
||
- `tls: certificate verify failed` → 需要`skip-cert-verify: true`
|
||
|
||
> 验证连通性(飞牛容器内 curl 测试)
|
||
>
|
||
>
|
||
|
||
```bash
|
||
docker exec -it moviepilot curl -v --socks5-hostname 群晖IP:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDBKEY
|
||
```
|
||
|
||
---
|
||
|
||
# 3\. 根因分析
|
||
|
||
1. 飞牛 fnOS 自带 OVS 虚拟交换机,会拦截 UDP 数据包;家庭路由器 / 光猫也会限制 UDP 出站,Hysteria2(QUIC/UDP)无法正常建立隧道。
|
||
|
||
2. 飞牛 Docker 容器隔离:容器内程序不会自动复用宿主机代理,MoviePilot、TMM 裸网访问 TMDB,遭遇 DNS 污染 \+ SNI 阻断。
|
||
|
||
3. Mac、群晖网络环境 UDP 不受限,所以同样配置、同样节点可以正常工作。
|
||
|
||
> 最终方案思路:**不再在飞牛部署 Mihomo 代理**,采用双冗余架构:
|
||
> ✅ 主方案:飞牛容器内 MoviePilot/TMM 直接复用**群晖 Mihomo 的 SOCKS5 代理**
|
||
> ✅ 备用方案:CF Worker 中转 TMDB API,**完全不需要代理**,群晖 / 代理故障时兜底刮削。
|
||
>
|
||
>
|
||
|
||
---
|
||
|
||
# 4\. 方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理
|
||
|
||
## 4\.1 群晖 Mihomo 前置配置(必须)
|
||
|
||
群晖 Mihomo `config.yaml` 关键配置,**允许局域网访问**
|
||
|
||
```yaml
|
||
mixed-port: 7890
|
||
allow-lan: true
|
||
listen-address: 0.0.0.0
|
||
ipv6: false
|
||
```
|
||
|
||
> 要求:群晖防火墙放行 7890 端口;飞牛与群晖在同一局域网,无跨 VLAN 隔离。
|
||
>
|
||
>
|
||
|
||
## 4\.2 MoviePilot docker\-compose\.yml(飞牛 fnOS)
|
||
|
||
> 修改:`192.168.1.100` 替换为**群晖内网 IP**;修改 volume 路径为飞牛实际路径
|
||
>
|
||
>
|
||
|
||
```yaml
|
||
version: "3.8"
|
||
services:
|
||
moviepilot:
|
||
image: jxxghp/moviepilot:latest
|
||
container_name: moviepilot
|
||
restart: unless-stopped
|
||
ports:
|
||
- "3000:3000"
|
||
volumes:
|
||
- /volume1/moviepilot:/app/config
|
||
environment:
|
||
- TZ=Asia/Shanghai
|
||
# socks5h = 远端域名解析,规避DNS污染
|
||
- PROXY_HOST=socks5h://192.168.1.100:7890
|
||
# Github资源加速,解决插件下载失败
|
||
- GITHUB_PROXY=https://mirror.ghproxy.com/
|
||
network_mode: bridge
|
||
```
|
||
|
||
### MoviePilot WebUI 配置
|
||
|
||
- TMDB 地址保持官方默认,**PROXY\_HOST 已由环境变量注入,无需重复填写**
|
||
|
||
- 填入你的 TMDB API Key
|
||
|
||
> 启动命令:`docker-compose up -d`
|
||
>
|
||
>
|
||
|
||
## 4\.3 TinyMediaManager \(TMM\) docker\-compose\.yml(飞牛 fnOS)
|
||
|
||
```yaml
|
||
version: "3.8"
|
||
services:
|
||
tinymediamanager:
|
||
image: tinymediamanager/tinymediamanager:latest
|
||
container_name: tinymediamanager
|
||
restart: unless-stopped
|
||
ports:
|
||
- "4000:4000"
|
||
volumes:
|
||
- /volume1/tmm:/config
|
||
environment:
|
||
- TZ=Asia/Shanghai
|
||
- ALL_PROXY=socks5h://192.168.1.100:7890
|
||
- NO_PROXY=127.0.0.1,localhost,192.168.0.0/16
|
||
network_mode: bridge
|
||
```
|
||
|
||
### TMM WebUI 代理配置(推荐优先使用网页内配置,比环境变量更稳定)
|
||
|
||
- Proxy type: `SOCKS5`
|
||
|
||
- Host:群晖内网 IP
|
||
|
||
- Port:7890
|
||
|
||
- ✅ 勾选:Resolve hostnames remotely(远端域名解析,等价 socks5h)
|
||
|
||
## 4\.4 连通验证命令
|
||
|
||
```bash
|
||
docker exec -it moviepilot curl -v --socks5-hostname 192.168.1.100:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDB密钥
|
||
```
|
||
|
||
> 返回 JSON 代表链路正常。
|
||
>
|
||
>
|
||
|
||
---
|
||
|
||
# 5\. 方案二【备用兜底方案】Cloudflare Worker TMDB 中转(鉴权 \+ 缓存,无需代理)
|
||
|
||
> 适用场景:群晖关机、代理节点失效、UDP 链路彻底不可用。仅接管 TMDB 接口,Github、豆瓣等其他外网 API 仍然需要代理。
|
||
> 免费限制:CF Worker 免费版每日 10 万次请求,日常刮削完全够用。
|
||
>
|
||
>
|
||
|
||
## 5\.1 主中转 Worker 脚本(鉴权 \+ 缓存)
|
||
|
||
登录 Cloudflare 后台 → Workers \& Pages → 创建 Worker,清空原有代码粘贴下面代码
|
||
|
||
```javascript
|
||
export default {
|
||
async fetch(request, env) {
|
||
// ========== 自定义你的访问密钥,自行修改 ==========
|
||
const ACCESS_SECRET = "自定义随机密钥";
|
||
// 缓存有效期,单位秒:3600=1小时;600=10分钟;86400=24小时
|
||
const CACHE_TTL = 3600;
|
||
// ================================================
|
||
|
||
const auth = request.headers.get("X-Tmdb-Secret");
|
||
if (!auth || auth !== ACCESS_SECRET) {
|
||
return new Response("Access Denied", { status: 403 });
|
||
}
|
||
|
||
const targetHost = "api.themoviedb.org";
|
||
const url = new URL(request.url);
|
||
url.hostname = targetHost;
|
||
const newReq = new Request(url, request);
|
||
newReq.headers.set("Host", targetHost);
|
||
|
||
// GET请求开启缓存,提升速度、节约额度
|
||
if (request.method === "GET") {
|
||
const cacheKey = new Request(newReq.url, newReq);
|
||
const cache = caches.default;
|
||
let response = await cache.match(cacheKey);
|
||
|
||
if (!response) {
|
||
response = await fetch(newReq);
|
||
response = new Response(response.body, response);
|
||
response.headers.set("Cache-Control", `s-maxage=${CACHE_TTL}`);
|
||
await cache.put(cacheKey, response.clone());
|
||
}
|
||
return response;
|
||
}
|
||
// POST等其他请求直接透传,不缓存
|
||
return await fetch(newReq);
|
||
}
|
||
}
|
||
```
|
||
|
||
保存部署,得到 worker 域名,示例 `tmdb-proxy.xxx.workers.dev`
|
||
|
||
## 5\.2 缓存清理三种方案
|
||
|
||
1. **单影片临时绕过缓存(最简单)**
|
||
请求地址末尾追加:`&_nocache=随机数字`
|
||
示例:
|
||
`https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=xxx&_nocache=20260925`
|
||
|
||
2. **全局一键清空全部缓存(批量重刷媒体库)**
|
||
修改 Worker 代码任意一行,重新部署;CF 所有边缘节点缓存自动全部失效。
|
||
|
||
3. **精准单条缓存删除(进阶 Purge Worker)**
|
||
新建独立 Worker(tmdb\-purge),粘贴下面代码,密钥和主 Worker 保持一致
|
||
|
||
```javascript
|
||
export default {
|
||
async fetch(request, env) {
|
||
const ACCESS_SECRET = "和主Worker相同的密钥";
|
||
const auth = request.headers.get("X-Tmdb-Secret");
|
||
if (!auth || auth !== ACCESS_SECRET) {
|
||
return new Response("Access Denied", { status: 403 });
|
||
}
|
||
|
||
const url = new URL(request.url);
|
||
const targetPath = url.searchParams.get("path");
|
||
if (!targetPath) {
|
||
return new Response("Missing ?path=/3/movie/550", { status: 400 });
|
||
}
|
||
// 替换为你的主worker域名
|
||
const cacheUrl = new URL(`https://tmdb-proxy.xxx.workers.dev${targetPath}`);
|
||
const cacheReq = new Request(cacheUrl);
|
||
const cache = caches.default;
|
||
await cache.delete(cacheReq);
|
||
return new Response(`Purged: ${cacheUrl.toString()}`);
|
||
}
|
||
}
|
||
```
|
||
|
||
调用示例:
|
||
|
||
```bash
|
||
curl -v -H "X-Tmdb-Secret: 自定义随机密钥" "https://tmdb-purge.xxx.workers.dev/?path=/3/movie/550?api_key=你的TMDBKEY"
|
||
```
|
||
|
||
## 5\.3 MoviePilot 切换 CF Worker 配置
|
||
|
||
1. 清空 PROXY\_HOST(关闭代理)
|
||
|
||
2. TMDB API 地址:`https://tmdb-proxy.xxx.workers.dev/3`
|
||
|
||
3. 自定义请求头添加一行:
|
||
`X-Tmdb-Secret: 自定义随机密钥`
|
||
|
||
4. 保留原有 TMDB API Key
|
||
|
||
## 5\.4 TMM 切换 CF Worker 配置
|
||
|
||
1. TMDB API URL 替换为 worker 地址 `https://tmdb-proxy.xxx.workers.dev/3`
|
||
|
||
2. Custom HTTP Headers 添加:`X-Tmdb-Secret: 自定义随机密钥`
|
||
|
||
3. 关闭 TMM 内部代理设置
|
||
|
||
## 5\.5 curl 测试命令
|
||
|
||
```bash
|
||
curl -v -H "X-Tmdb-Secret: 自定义随机密钥" "https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=你的TMDBKEY"
|
||
```
|
||
|
||
返回 JSON 即为正常。
|
||
|
||
---
|
||
|
||
# 6\. 两套方案切换规则
|
||
|
||
|方案|适用场景|优点|缺点|
|
||
|---|---|---|---|
|
||
|复用群晖 Mihomo(主方案)|日常长期使用,群晖保持开机|全覆盖 TMDB/Github/ 豆瓣,无额度限制,速度稳定|依赖群晖在线,群晖关机则刮削失效|
|
||
|CF Worker 中转(备用)|群晖关机、代理节点故障、UDP 被拦截|零代理依赖,不受 UDP/OVS 限制,自带缓存加速|仅 TMDB 接口生效,CF 免费版有每日额度上限|
|
||
|
||
> 使用策略:日常使用主方案;代理故障 / 群晖关机,临时切换到 CF Worker 兜底刮削。
|
||
>
|
||
>
|
||
|
||
---
|
||
|
||
# 7\. 统一故障排查清单
|
||
|
||
1. ❌ 容器内不要填写`127.0.0.1`作为代理地址,容器内 \[127\.0\.0\.1\]\(127\.0\.0\.1\) 指向容器自身,必须填写群晖内网 IP。
|
||
|
||
2. ✅ 群晖 Mihomo 必须开启`allow-lan: true`,监听地址`0.0.0.0`,否则飞牛无法访问 7890 端口。
|
||
|
||
3. ✅ 飞牛环境关闭 IPv6,规避 TLS 握手异常。
|
||
|
||
4. ❌ 放弃飞牛本地部署 Hysteria2,OVS \+ 路由器 UDP 拦截属于硬限制。
|
||
|
||
5. ✅ MoviePilot/TMM 优先使用软件原生内置代理配置,优于`ALL_PROXY`环境变量。
|
||
|
||
6. 测试链路优先使用`--socks5-hostname`,远端解析域名,规避 DNS 污染。
|
||
|
||
7. 代理测试失败优先查看 Mihomo debug 日志,定位是 UDP 超时、证书错误还是鉴权错误。
|
||
|
||
---
|
||
|
||
# 8\. 附录:常用命令汇总
|
||
|
||
```bash
|
||
# 查看docker容器
|
||
docker ps | grep mihomo
|
||
docker ps | grep moviepilot
|
||
# 实时查看mihomo日志
|
||
docker logs -f --tail 100 mihomo
|
||
# 进入moviepilot容器curl测试代理连通
|
||
docker exec -it moviepilot curl -v --socks5-hostname 群晖IP:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDBKEY
|
||
# 测试CF Worker中转
|
||
curl -v -H "X-Tmdb-Secret: 自定义密钥" "https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=你的TMDBKEY"
|
||
```
|
||
|
||
---
|
||
|
||
如果你想要,我可以再输出 **Markdown 纯文本版本**(不带任何 canvas 标签,直接复制到 Typora/Obsidian/ 语雀保存)。你要 Markdown 版本吗?
|
||
|
||
> (注:部分内容可能由 AI 生成)
|