14 KiB
NAS媒体刮削TMDB接口访问问题完整排查+落地文档
NAS 媒体刮削 TMDB 接口访问问题完整排查 + 落地文档
文档来源:本次全部对话记录整理,包含:故障现象、完整排错过程、根因分析、两套可落地解决方案、配置模板、验证命令、故障清单 环境:MacOS Clash Verge Rev、群晖 NAS(Mihomo+Hysteria2 正常)、飞牛 fnOS(Docker 部署 MoviePilot、tinyMediaManager)
目录
-
故障现象汇总
-
前期网络排错全过程(curl、TLS、Hysteria2 排查)
-
根因分析
-
方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理
-
方案二【备用兜底方案】Cloudflare Worker TMDB 中转(鉴权 + 缓存,无需代理)
-
两套方案切换规则
-
统一故障排查清单
-
附录:测试命令、参考脚本
1. 故障现象汇总
1.1 网络侧现象
-
MacOS 客户端:Clash Verge Rev(Mihomo 内核),Hysteria2 节点,访问
api.themoviedb.org正常,TMDB 接口可访问。 -
群晖 NAS:部署 Mihomo,同一份 config.yaml、相同内核版本,Hysteria2 节点正常,MoviePilot、TinyMediaManager 媒体刮削,TMDB 接口调用全部正常。
-
飞牛 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 测试过程关键现象
-
裸网直接访问
api.themoviedb.org:443:TCP 能建立连接,TLS 握手中断,SNI 被网络拦截。 -
使用本地 SOCKS5 代理(7890),未使用
--socks5-hostname:本地解析域名,拿到污染 IP,握手失败;使用--socks5-hostname,域名交由代理远端解析。 -
Hysteria2 依赖 UDP QUIC 协议;飞牛 fnOS 的 OVS 虚拟交换机 + 家庭路由器会拦截 UDP 出站,导致 HY2 QUIC 握手超时。
-
飞牛 Docker 容器不会自动继承宿主机的代理,容器内程序(MoviePilot/TMM)不会自动走宿主机 Mihomo。
2. 前期网络排错全过程记录
2.1 基础 curl 裸网测试
# 测试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 端口)
# 错误:本地解析域名
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)
- 修改 Mihomo 配置,开启 debug 日志
log-level: debug
external-controller: 127.0.0.1:9090
- 查看容器实时日志
# 查看容器名
docker ps | grep mihomo
# 实时跟踪日志
docker logs -f --tail 100 mihomo
# 导出日志到文件
docker logs mihomo > mihomo-debug.log
- 关键词识别
-
quic: connection timed out→ UDP 出站被拦截(本次核心问题) -
unsupported proxy type: hysteria2→ Mihomo 内核版本过低 -
tls: certificate verify failed→ 需要skip-cert-verify: true
验证连通性(飞牛容器内 curl 测试)
docker exec -it moviepilot curl -v --socks5-hostname 群晖IP:7890 https://api.themoviedb.org/3/movie/550?api_key=你的TMDBKEY
3. 根因分析
-
飞牛 fnOS 自带 OVS 虚拟交换机,会拦截 UDP 数据包;家庭路由器 / 光猫也会限制 UDP 出站,Hysteria2(QUIC/UDP)无法正常建立隧道。
-
飞牛 Docker 容器隔离:容器内程序不会自动复用宿主机代理,MoviePilot、TMM 裸网访问 TMDB,遭遇 DNS 污染 + SNI 阻断。
-
Mac、群晖网络环境 UDP 不受限,所以同样配置、同样节点可以正常工作。
最终方案思路:不再在飞牛部署 Mihomo 代理,采用双冗余架构: ✅ 主方案:飞牛容器内 MoviePilot/TMM 直接复用群晖 Mihomo 的 SOCKS5 代理 ✅ 备用方案:CF Worker 中转 TMDB API,完全不需要代理,群晖 / 代理故障时兜底刮削。
4. 方案一【主方案|推荐日常使用】飞牛容器复用群晖 Mihomo 代理
4.1 群晖 Mihomo 前置配置(必须)
群晖 Mihomo config.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 路径为飞牛实际路径
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)
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 连通验证命令
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,清空原有代码粘贴下面代码
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 缓存清理三种方案
-
单影片临时绕过缓存(最简单) 请求地址末尾追加:
&_nocache=随机数字示例:https://tmdb-proxy.xxx.workers.dev/3/movie/550?api_key=xxx&_nocache=20260925 -
全局一键清空全部缓存(批量重刷媒体库) 修改 Worker 代码任意一行,重新部署;CF 所有边缘节点缓存自动全部失效。
-
精准单条缓存删除(进阶 Purge Worker) 新建独立 Worker(tmdb-purge),粘贴下面代码,密钥和主 Worker 保持一致
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()}`);
}
}
调用示例:
curl -v -H "X-Tmdb-Secret: 自定义随机密钥" "https://tmdb-purge.xxx.workers.dev/?path=/3/movie/550?api_key=你的TMDBKEY"
5.3 MoviePilot 切换 CF Worker 配置
-
清空 PROXY_HOST(关闭代理)
-
TMDB API 地址:
https://tmdb-proxy.xxx.workers.dev/3 -
自定义请求头添加一行:
X-Tmdb-Secret: 自定义随机密钥 -
保留原有 TMDB API Key
5.4 TMM 切换 CF Worker 配置
-
TMDB API URL 替换为 worker 地址
https://tmdb-proxy.xxx.workers.dev/3 -
Custom HTTP Headers 添加:
X-Tmdb-Secret: 自定义随机密钥 -
关闭 TMM 内部代理设置
5.5 curl 测试命令
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. 统一故障排查清单
-
❌ 容器内不要填写
127.0.0.1作为代理地址,容器内 [127.0.0.1](127.0.0.1) 指向容器自身,必须填写群晖内网 IP。 -
✅ 群晖 Mihomo 必须开启
allow-lan: true,监听地址0.0.0.0,否则飞牛无法访问 7890 端口。 -
✅ 飞牛环境关闭 IPv6,规避 TLS 握手异常。
-
❌ 放弃飞牛本地部署 Hysteria2,OVS + 路由器 UDP 拦截属于硬限制。
-
✅ MoviePilot/TMM 优先使用软件原生内置代理配置,优于
ALL_PROXY环境变量。 -
测试链路优先使用
--socks5-hostname,远端解析域名,规避 DNS 污染。 -
代理测试失败优先查看 Mihomo debug 日志,定位是 UDP 超时、证书错误还是鉴权错误。
8. 附录:常用命令汇总
# 查看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 生成)