这几天我一直在和一条很别扭的播放链路较劲。
本来想得挺简单:把网盘里的资源通过 CMS + strm + Emby + 反代 这一套挂起来,再顺手让爆米花和 VidHub 也能一起用,事情就结束了。结果真动手之后才发现,这根本不是“修一个点”的问题,而是一边拽就会带出来一整串。
最后总算是修顺了:Web 能播,爆米花能播,VidHub 也通了,而且主入口继续保留在高位端口,不改成 443;真正的大流量也尽量还是走 302 到网盘,不让 VPS 自己苦哈哈地扛视频流。
这篇还是按博客来写,不当交接文档。公网 IP、域名、账号密码这些敏感东西我都不往里放,只记真正值得记的坑和解法。
一开始我以为只是 Emby 播不动
最初看上去特别像是 Emby 自己抽风:能刮削,能识别媒体,但一到播放就不对劲。可真往下拆之后,很快就发现事情没这么单纯。
真正的问题,至少是三层叠在一起的:
.strm里有一批地址从一开始就写错了,指向的不是正确的 CMS 302 出口。- Emby 容器自己的代理环境也不干净,它去请求自己的链路时,反而被自己坑了。
- 最烦的是第三方客户端根本不一定按服务端给的路径走,它们会自己改地址,最后把流量又绕回 Emby。
也就是说,这不是一个“播放器不行”的问题,而是一整条链路里,每一层都刚好有一点别扭,最后一起爆了。
第一刀,先砍 strm 和 Emby 自己
我最先下手的是 .strm。因为这个东西一旦源头写错,后面再怎么修都像在补漏水的屋顶,根本补不干净。
之前一批 .strm 写的是某个直接暴露出来的 CMS 端口,但那个口子并不是最终应该给客户端走的外部 302 出口。这样一来,Emby 虽然表面上能识别媒体,真到播放时还是会在后面翻车。
所以这一层我做得很直接:
- 把 CMS 里和 302 相关的外部域名配置修回统一入口。
- 批量把错误的
.strm地址全部替换掉。 - 在反代层把
/d/、/s/这些 CMS 302 路由都补齐。
但很快又发现,光修 .strm 还不够。Emby 容器里原本带着一套代理环境变量,它一边请求自己的反代入口,一边又会在后续跟随到网盘 CDN 时被错误带去走代理。这个坑非常阴,表面现象就是 stream.strm 500、Range 超时、日志里一堆看起来云里雾里的失败。
我后面把 Emby 的环境重新理了一遍,该放进 NO_PROXY 的域名和目标全补进去,再按新配置重建容器。到这一步之后,链路终于像样了:
HEAD /stream.strm能回200。- 带
Range的请求能稳定回206。 - Web 播放恢复正常。
这时候我心里才算有点底:至少 Emby 自己这层已经不是问题核心了。
第二刀,补一补第三方客户端那些奇奇怪怪的小脾气
Web 修好之后,爆米花和 VidHub 还是不老实。它们和浏览器访问 Emby 的方式完全不是一回事,尤其是探活和登录这一段,经常会走一些很“客户端”的路数。
比如有些接口,浏览器发 GET 没问题,某些客户端却先来个 HEAD。偏偏 Emby 某些版本在这些公共接口上,GET 和 HEAD 的表现又不一致。结果就是:你明明服务还活着,但客户端那边看起来像服务器挂了。
这个问题说大不大,说烦是真烦。后来我干脆在 OpenResty 这一层给常见探活接口做兼容,让 GET 和 HEAD 都能正常通过,至少别卡在“还没开始登录就先说你不在线”这种离谱环节上。
登录这里也有个坑。有些客户端去打 AuthenticateByName 的时候,自己没有带合规的 X-Emby-Authorization,于是即使用户名密码本身没错,Emby 还是会因为参数不完整直接翻脸。
这个在浏览器里你不太会碰上,但在第三方客户端里就是实打实会遇到。最后我的处理方式也很简单粗暴:客户端没带够,我就在反代层补一个兼容头再交给 Emby。至少先把登录这一步放过去,不要卡死在门口。
最难缠的,其实不是“连不上”,而是“连上以后开始中转”
真正让我头大的,不是客户端报错,而是它们有时候明明已经连上了,结果播放一拉起来,整条链路就开始往错误的方向跑。
理想状态当然是最舒服的:客户端拿到 CMS 给的 302 路径,然后自己一路跟到网盘,服务器只负责指路,不负责出力。
可现实是,第三方客户端有时候根本不按服务端给的路径来。PlaybackInfo 里明明已经有可以直接用的远程播放地址了,它们还是会自己手动拼成 /Videos/.../stream.xxx 这种地址再去找 Emby。
一旦它们这么干,事情就会变成:
- 客户端去请求 Emby。
- Emby 再去拉 CMS 的
/d/...。 - 最后视频流量开始走 VPS 中转。
这时候最直观的感受就是速度掉得离谱,轻量服务器的带宽和流量也会一起遭殃。最烦的是,这种坏链路有时候表面上还“不是完全不能播”,只是慢得像在受刑。
后来我干了两件很关键的事:
- 先把
PlaybackInfo改写掉,返回给客户端的是一条我可控的播放路径,并把原始的orig_d保留下来。 - 再对
/Videos/.../stream.xxx做一层反代侧兜底。客户端就算非要自己拼这个地址,我也在反代层把它重新引回 CMS 的原始 302 路径上。
这一刀下去之后,链路终于不再那么容易跑偏。判断它到底有没有回正,其实看日志最清楚:
- 如果是好链路,反代层会对
/Videos/...返回302,CMS 再对/d/...返回302,Emby 只做元数据和播放进度。 - 如果是坏链路,Emby 日志里就会出现它自己去拉远端媒体、自己去请求
/d/...的记录。那说明它又被迫下场当搬运工了。
VidHub 最后卡住的地方,居然是“地址得像同一个人说的话”
后面还有一个让我印象很深的坑:同一个服务,如果客户端最开始是从 IP + HTTP + 28080 这个入口进来的,服务端后面却突然返回成“域名 + HTTPS + 同端口”这一套,有些客户端真的会当场别扭起来。
爆米花对这种混用还稍微宽容一点,VidHub 就明显敏感得多。一旦入口前后说法不一致,它就会出现那种特别烦的状态:
- 看起来像是已经连上了。
- 登录也不一定报错。
- 但播放就是不对,或者行为非常不稳定。
最后我才真正确认,VidHub 这边最关键的修法,根本不是继续换账号密码,也不是继续折腾 Emby 本体,而是把整个链路对外表现出来的地址形态统一掉。
说白了就是:客户端如果是从 IP + HTTP + 28080 进来的,那后面的 System/Info/Public、PlaybackInfo、/Videos/...、orig_d、/d/...,也尽量都保持这一套说法。不要前脚让人从一个口进来,后脚又拿另一张脸跟它说话。
这一步听起来不像什么“大技术点”,但对客户端兼容来说,真的非常要命。尤其 VidHub 这种比较挑的,地址前后是不是一个逻辑,比我一开始想象的重要得多。
折腾到最后,终于像个能长期跑的样子了
这一轮全部收完之后,结果总算是顺眼了:
- Web 正常播。
- 爆米花正常播。
- VidHub 也正常连、正常播。
- 主入口继续保留高位端口,不动 443 这条主思路。
- 大部分视频流量尽量走
302到网盘,不让 VPS 长时间中转。
如果让我现在回头用一句话总结这次排障,那大概就是:
这条链路真正被修顺,不是因为我把某一个服务修好了,而是因为我终于把 strm、CMS、Emby、反代和客户端这些互相牵扯的地方,慢慢拽成了一条线。
顺手记几句,给以后再踩坑的自己看
.strm能刮削,不代表播放链路就是对的。- 容器里的代理环境变量,真的很容易误伤它自己。
- 第三方客户端不一定会按服务端给的最佳路径走,很多时候必须在反代层兜底。
- 像 VidHub 这种客户端,地址形态前后一致,和“能不能播”几乎是同等级的重要性。
- 如果目标是省 VPS 流量,就一定要盯日志,确认最后跑的是
302 -> 网盘,而不是 Emby 自己去拉文件。
这篇先记到这里。后面如果我把这套链路继续补成更省心的版本,比如自动巡检、播放异常提醒,或者整理出一份更适合复用的模板,我再接着写下一篇。
