心梦后花园

Back

大部分远程 Emby 的线路都在国外,国内连接基本都需要代理,在家里电视上看视频还得单独开代理,不太方便。于是买了一台 9929 线路的服务器,用 Nginx 做了一层反向代理:图片和静态资源留在本机缓存,视频音频直接 302 给客户端,另外用一个开关文件在「直连」和「本机中转」之间切换。这里把当时的配置记一下;加开关主要是为了在 VPS 流量不够的时候切回 Emby 自己的线路。

整体思路#

下面的配置里,emby.example.com 是我们自己的域名,https://origin.example.net 是 Emby 的登录地址,https://video.example.net 是实际播放地址(可能跟登录地址一样,也可能不一样),Nginx 按请求类型分流:

请求处理方式
/emby/**/Images/** 图片资源本机反代,写入本地缓存
/videos/**、/audio/**302 到源站,本机不转发字节,有开关配置
其余 UI/API本机反代
存在开关文件全部改为本机转发,并改写上游返回的地址

另外还有两个统一处理:把 Dart、axios 这类 UA 换成普通浏览器 UA——有的站点会限制 UA,之前折腾一直有问题,就是部分客户端的 UA 被 Emby 站点拦截了;反代时把客户端的 IP 头抹掉。

完整配置#

配置里的域名、证书路径和日志路径都换成了占位符:

几个关键点#

UA 替换#

map 必须写在 server 块外层,default 保留客户端原始 UA,命中 Dart 或 axios 时替换成桌面版 Chrome。后面所有 proxy_set_header User-Agent $safe_user_agent; 都直接复用这个变量。

图片缓存#

proxy_cache_path 划分了 50M 的索引区和 2G 的磁盘上限,30 天不访问自动清理。图片 location 里用 proxy_ignore_headers 忽略上游的 Cache-Control、Expires 和 Set-Cookie,再用 proxy_cache_valid 固定缓存 30 天;proxy_cache_lock on 保证同一张海报并发回源时只打一次上游。

直连与中转开关#

if (-f /etc/nginx/emby_vps_proxy.on) 检查开关文件,存在就 return 418,由 error_page 418 = @emby_vps; 转到中转用的命名 location。if 里只放 return,是 Nginx 里少数可以放心使用的写法。开关文件本身只是个普通文件,直接 touch /etc/nginx/emby_vps_proxy.on 创建即可:有文件就走本机中转,没有就按 Emby 原本的线路走。

直连模式下,/videos/ 和 /audio/ 直接 302 到源站,其余请求才反代。

中转模式#

中转时会改写上游返回的地址:proxy_redirect 处理 Location 头,sub_filter 处理 JSON 里硬编码的绝对地址。sub_filter 默认只作用于 text/html,所以要显式加上 application/json text/plain;同时反代时统一 Accept-Encoding "",避免上游返回 gzip 导致替换失效。

几个当时踩到的坑#

  • 没配 resolver / DNS 解析失败导致 Nginx 起不来:proxy_pass 直接写死域名时,Nginx 只在启动和重载时解析一次。那段时间上游 DNS 出问题,重启 Nginx 直接报 host not found in upstream,整台机器上的站点一起挂掉,遇到过好几次。改成「变量 + resolver」后,解析推迟到请求时,valid=30s 还能跟着 DNS 变化走;但变量形式下如果忘了写 resolver,请求会直接 502,error.log 里报 no resolver defined to resolve ...。
  • UA 不对会被上游拦:部分客户端用的是 Dart、axios 这类 UA,有的 Emby 站点会直接拒绝,表现是接口 403、海报空白或者播放失败,日志里看不出什么线索,当时排查了半天才想到去抓请求头。最后用 map 把这些 UA 统一换成桌面版 Chrome,问题才消失。
  • add_header 是全有或全无:只要某个 location 自己写了任意一条 add_header,server 级的 add_header 就全部不继承。图片缓存和 /video-proxy/ 这两个 location 上的 HSTS、X-Frame-Options 等安全头其实是丢掉的,需要重新补一遍。
  • :443 写死:proxy_redirect 和 sub_filter 的匹配串里带了默认端口,上游如果生成的是不带端口的 URL 就匹配不上,两种写法最好都加上。
  • sub_filter 的替换串:匹配串没带结尾斜杠、替换串带了,遇到 /emby/... 会拼出双斜杠。默认 merge_slashes on 会兜住,但写全更稳妥。
  • 缓存和 gzip:图片缓存 location 里忘了清 Accept-Encoding,客户端带 gzip 时可能把 gzip 变体写进缓存,之后碰到不支持 gzip 的客户端就会出问题。
  • 302 与 POST:如果把 API 也改成 302,多数客户端会把 POST 降级成 GET,登录和播放进度上报会失败;只对媒体路径做 302 更安全。

最后#

这套配置的思路不复杂:能让客户端直连的就直连,必须经过本机的才经过本机。图片体积小、请求量大,放本地缓存收益最明显;视频动辄几个 G,302 出去能省下大部分流量。开关文件则留了一个后手,线路出问题时不用改配置,touch 一下就能切回中转。

Nginx 反代 Emby:图片缓存、视频直连与线路切换
https://www.liyp.cc/blog/emby-nginx-reverse-proxy-image-cache
Author 万古一梦
Published at 2026年11月3日
Comment seems to stuck. Try to refresh?✨