banner
约 4,200 字
14 分钟

DecoTV(原 KatelyaTV)部署教程:Docker 自建影视聚合站

DecoTV(原 KatelyaTV)部署教程:Docker 自建影视聚合站

摘要

KatelyaTV 已更名 DecoTV:镜像、环境变量与部署方式全换,且只支持 Docker。含三种存储对比、空壳项目配置文件写法与排错清单。

DecoTV(原 KatelyaTV)部署教程:Docker 自建影视聚合站

如果你收藏过 KatelyaTV 的教程,先说结论:这个项目改名了。它现在叫 DecoTV,仓库、镜像地址、环境变量、支持的部署方式全都换过一轮。照着旧教程走,第一步 docker pull 就会失败。

先记住三处最容易踩坑的变更:① 项目更名,仓库与镜像地址都换了;② Cloudflare Pages + D1 方案已不存在;③ 部署完成只是一个「空壳」,没有内置播放源

DecoTV 暗夜模式主界面:顶部导航、聚合搜索入口与「继续观看」
DecoTV 暗夜模式主界面:顶部导航、聚合搜索入口与「继续观看」

一、先搞清楚:改了什么

这一步别跳过,它决定了后面能不能跑起来。

项目

旧(KatelyaTV)

现在(DecoTV)

仓库地址

katelya77/KatelyaTV

Decohererk/DecoTV

Docker 镜像

ghcr.io/katelya77/katelyatv:latest

ghcr.io/decohererk/decotv:latest

技术底座

Next.js 14

Next.js 16 + App Router + Turbopack,Tailwind CSS 4

存储类型

d1

localstorage / redis / kvrocks / upstash没有 d1

部署方式

Docker / Pages / Vercel

仅 Docker(官方原话:本项目仅支持 Docker 或其他基于 Docker 的平台部署)

注册开关

NEXT_PUBLIC_ENABLE_REGISTER

NEXT_PUBLIC_ENABLE_REGISTRATION,且日常启停在后台操作

两个直接后果:

  1. ghcr.io/katelya77/katelyatv 这个镜像不要再用了。 旧仓库仍在,但最后提交是 2025-10-01,新功能和新修复都只在 DecoTV。

  2. 「Cloudflare Pages + D1」那套做法已经作废。 现在存储层只有上面四种,注册一个 D1 数据库再绑定 wrangler.toml 是白做工。想省钱就别在这条路上耗时间。

顺带说清楚「更名」的性质:DecoTV 是原 KatelyaTV 作者的延续项目(README 标注「【原 KatelyaTV】」),但代码底座换成了 LunaTV 的二次开发版。所以它不是旧项目换了个名字那么简单——版本号、配置结构、数据库初始化都和旧版不通用

二、部署前必须接受的三件事

先看清楚,再决定要不要装。这三条不是劝退,是省事。

第一,只能 Docker。 官方没有提供 Serverless / 静态托管的一键部署路径。好处是环境一致、附带 FFmpeg;代价是你得有一台能跑 Docker 的机器——VPS、NAS(飞牛 OS / 群晖)、软路由、树莓派都行。

第二,部署完成是一个「空壳」。 这句话官方用加粗写在 README 里:「部署后项目为空壳项目,无内置播放源和直播源,需要自行收集配置。」 也就是说装完打开是能用的界面,但搜不到任何片子——播放源要你自己在后台填 JSON 配置。

第三,它是自用工具,不是公开服务。 官方声明仅供学习与个人使用、请勿公开分享或用于商业用途。装完请设强密码、关掉公网注册,并且自行承担资源合法性的判断责任——这条我会在最后一节展开。

三、部署前准备

项目

说明

一台跑 Docker 的机器

VPS / NAS / 软路由 / 树莓派均可,架构 x86_64 或 arm64

内存

建议 ≥1GB 可用(Next.js 运行时 + 可选 FFmpeg)

一个端口

默认 3000,被占用就换映射端口

存储选择

单人体验用 localstorage;想多端同步用 Kvrocks / Redis / Upstash

管理密码

必填项,没有默认值,不设置就等于门户大开

存储方案怎么选,一句话:单人单设备 → localstorage;家庭 / 多设备同步 → Kvrocks;已有 Redis → Redis;不想自己维护数据库 → Upstash。

  • localstorage:数据存浏览器,不需要任何数据库,最省事,但换浏览器 / 清缓存就丢配置,也不支持多端同步。

  • Kvrocks:官方推荐。兼容 Redis 协议但支持持久化,适合长期跑。

  • Redis:能用,官方明确提示「有一定的丢数据风险」,务必自己开持久化。

  • Upstash:托管式 Redis,走 REST API,不想自己运维数据库时选它。

四、方案 A:Docker Run 最简部署(先跑起来看效果)

只想先看看这东西长什么样,用这种方式,三行命令:

bash
docker run -d \
  --name decotv \
  -p 3000:3000 \
  -v decotv-downloads:/app/.cache/ffmpeg-downloads \
  -e PASSWORD=你的管理密码 \
  ghcr.io/decohererk/decotv:latest

然后浏览器打开 http://你的机器IP:3000,用 PASSWORD 里设的密码登录。

几个细节:

  • -v 那行别省。 它把 /app/.cache/ffmpeg-downloads 挂到具名卷上,否则容器一重建,用 FFmpeg 转存下来的文件全没。

  • 这个模式下不需要设 USERNAME,也不需要 NEXT_PUBLIC_STORAGE_TYPE 和任何数据库连接变量。官方在文档里专门列了「不需要」清单,多填反而容易出问题。

  • PASSWORD 是唯一的必填项。 忘了设,任何人都能进你的后台。

五、方案 B:Docker Compose + Kvrocks(长期使用推荐)

打算长期跑,用这套。Kvrocks 与主程序在同一网络里,配好就能用:

YAML
services:
  decotv-core:
    image: ghcr.io/decohererk/decotv:latest
    container_name: decotv-core
    restart: on-failure
    ports:
      - '3000:3000'
    environment:
      - USERNAME=admin
      - PASSWORD=admin_password
      - NEXT_PUBLIC_STORAGE_TYPE=kvrocks
      - KVROCKS_URL=redis://decotv-kvrocks:6666
    networks:
      - decotv-network
    depends_on:
      - decotv-kvrocks
  decotv-kvrocks:
    image: apache/kvrocks
    container_name: decotv-kvrocks
    restart: unless-stopped
    volumes:
      - kvrocks-data:/var/lib/kvrocks
    networks:
      - decotv-network
networks:
  decotv-network:
    driver: bridge
volumes:
  kvrocks-data:

保存为 docker-compose.yml 后:

bash
docker compose up -d
docker compose ps
docker compose logs -f decotv-core

注意 KVROCKS_URL 用的是 redis:// 前缀,端口是 Kvrocks 默认的 6666,不是 Redis 的 6379。这两处写错,容器会一直重启。

数据库模式下 USERNAMEPASSWORD 都是必填(官方文档表格原文:USERNAME 在数据库模式必填,本地模式可省略)。PASSWORD 请务必改掉示例里的 admin_password

六、方案 C:Redis 与 Upstash

已有 Redis 实例,把存储类型换成 redis

YAML
services:
  decotv-core:
    image: ghcr.io/decohererk/decotv:latest
    container_name: decotv-core
    restart: on-failure
    ports:
      - '3000:3000'
    environment:
      - USERNAME=admin
      - PASSWORD=admin_password
      - NEXT_PUBLIC_STORAGE_TYPE=redis
      - REDIS_URL=redis://decotv-redis:6379
    networks:
      - decotv-network
    depends_on:
      - decotv-redis
  decotv-redis:
    image: redis:alpine
    container_name: decotv-redis
    restart: unless-stopped
    networks:
      - decotv-network
    volumes:
      - ./data:/data      # 务必开持久化,否则升级或重启后数据丢失
networks:
  decotv-network:
    driver: bridge

不想自己维护数据库,用 Upstash:先去 upstash.com 注册并新建一个 Redis 实例,复制它的 HTTPS ENDPOINTTOKEN,然后:

YAML
services:
  decotv-core:
    image: ghcr.io/decohererk/decotv:latest
    container_name: decotv-core
    restart: on-failure
    ports:
      - '3000:3000'
    environment:
      - USERNAME=admin
      - PASSWORD=admin_password
      - NEXT_PUBLIC_STORAGE_TYPE=upstash
      - UPSTASH_URL=上面 https 开头的 HTTPS ENDPOINT
      - UPSTASH_TOKEN=上面的 TOKEN

这里有个高频错误:Upstash 走的是 REST API,变量名是 UPSTASH_URL + UPSTASH_TOKEN不是 UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN,也不是 Redis 连接字符串。抄别的项目配置时特别容易混。

七、可选:免登录家庭模式

默认访问模式是 password,必须登录。如果只在家里局域网 / NAS / 电视盒子上用,可以让它免登录:

YAML
services:
  decotv:
    image: ghcr.io/decohererk/decotv:latest
    container_name: decotv
    restart: unless-stopped
    ports:
      - '3000:3000'
    environment:
      - NEXT_PUBLIC_AUTH_MODE=public
    volumes:
      - decotv-downloads:/app/.cache/ffmpeg-downloads
volumes:
  decotv-downloads:

这条开关有一个必须知道的边界:设为 public 后,/admin 后台和 /api/admin/* 默认仍然需要登录。只有你再额外设 PUBLIC_ALLOW_ADMIN=true,才会连后台一起免登录——官方对它的评价是「该开关风险极高」,所以公网环境千万别开

八、首次进入:必做的三件事

容器起来了、界面能打开了,先别急着找片源。按顺序做这三步。

第一步,登录。PASSWORD(数据库模式还要 USERNAME)。如果登录成功但操作仍报 401,多半是三种原因:清一次浏览器 Cookie 重登;检查是否误设了 REDIS_URL 等多余数据库变量;反向代理漏传 X-Forwarded-Proto(见第十节)。

第二步,填配置文件——这是「空壳」变「能用」的关键。/admin 后台找到配置文件设置,填一段 JSON:

JSON
{
  "cache_time": 7200,
  "api_site": {
    "dyttzy": {
      "api": "http://xxx.com/api.php/provide/vod",
      "name": "示例资源",
      "detail": "http://xxx.com"
    }
  },
  "custom_category": [
    {
      "name": "华语",
      "type": "movie",
      "query": "华语"
    }
  ]
}

字段含义:

  • cache_time:接口缓存时间,单位秒。

  • api_site:资源站列表,键名用小写字母和数字api 填资源站的 vod JSON 接口根地址;name 是界面上显示的名字;detail 可选,给那些无法从 API 取到剧集详情的站点补一个网页地址用于爬取。

  • custom_category:自定义导航分类,以 type + query 作唯一标识。typemovietvquery 是去豆瓣搜索的关键词。

DecoTV 支持标准的苹果 CMS V10 接口格式,所以绝大多数 api.php/provide/vod 类资源站可以直接填。custom_category 的可选值官方列了一批,movie 下有热门、最新、经典、豆瓣高分、冷门佳片、华语、欧美、韩国、日本、动作、喜剧等;tv 下有热门、美剧、英剧、韩剧、日剧、国产剧、港剧、日本动画、综艺、纪录片。也可以直接填「哈利波特」这种关键词,等同于豆瓣搜索。

第三步,收尾安全配置。 把公网注册关掉(后台「用户配置 → 公开注册」)。注册功能本身只支持 Redis / Upstash / Kvrocks 存储,localstorage 模式没有多用户能力;官方建议默认关闭、需要时临时开、用完立刻关。

九、进阶配置:四个值得开的功能

TMDB 元数据增强。 豆瓣在欧美 / 日韩内容上信息偏薄,可以用 TMDB 补齐海报、背景图和简介。到 TMDB 后台申请 API Key,在环境变量或后台「TMDB 配置」里填 TMDB_API_KEY,如果部署环境连不上 TMDB,再配 TMDB_PROXY(正向)或 TMDB_REVERSE_PROXY(反向,优先级更高)。填完记得点一下后台的「TMDB 连通性测试」。不配也不影响原有豆瓣链路,属于纯增强。

弹弹play 弹幕。 这里有个容易误解的地方:官方 Docker 镜像并不会自动接入作者的公共中继,一是避免消耗免费额度,二是密钥打进公开镜像本来就不安全。所以 Docker 部署要么在后台配第三方弹幕节点,要么自己申请凭证:

env
DANDANPLAY_APP_ID=在DevCenter申请的AppId
DANDANPLAY_APP_SECRET=有效AppSecret

凭证只能放服务端环境变量,绝不能改成 NEXT_PUBLIC_* 前缀——那样会直接暴露给浏览器。运行时用 --env-file 注入,别提交进 Git:

bash
docker run --env-file .env.docker.local -p 3000:3000 decotv

PanSou 网盘搜索。 先部署一个 fish2018/pansou,确认 https://你的地址/api/health 能访问;然后到 DecoTV 后台「PanSou 配置」填服务地址,先做连通性测试再保存。如果 PanSou 开了 AUTH_ENABLED=true,可以填用户名密码让它自动换 JWT,也可以直接填 JWT。

私人影库。 支持接入 OpenList、小雅 Alist、Emby、Jellyfin,配好后前台会自动出现「我的影库」入口。建议同时开 TMDB —— OpenList 文件名里的 {tmdb-xxxx} 或 Emby/Jellyfin 的 ProviderIds.Tmdb 能直接命中精准元数据,省掉大量手动修正。

十、反向代理与 HTTPS:两个最容易踩的坑

这两个坑都跟「协议判断」有关,表现却完全不同。

坑一:登录后仍提示 401。 原因通常是反代没把外部访问协议传给容器。DecoTV 会根据请求 URL、X-Forwarded-ProtoX-Forwarded-Host 或标准 Forwarded 头来判断真实协议;判断失败,登录 Cookie 就设不上。Nginx / OpenResty 记得加:

nginx
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

坑二:播放时丢端口。 如果你用 https://域名:非443端口 这种反代,必须传带端口的 $http_host(就是上面第一行)。否则浏览器后续请求 m3u8 代理地址时会把端口丢掉,播放直接断。

另外理解一下 Cookie 行为,排查时有用:HTTPS 访问会设置 Secure Cookie;HTTP 局域网直连和 HTTP 反代不会设置 Secure——这是刻意的设计,为了让局域网纯 HTTP 也能正常登录。不要只看容器内的 NODE_ENV=production 来判断访问协议,那个值跟外部协议无关。

十一、TVBox 与 Android TV

TVBox:项目自带配置接口,详细功能在后台的「TVbox 配置」页面,仓库里另有一份 TVBox配置优化说明.md 值得一读。

Android TV:可以配合 OrionTV 使用,把 DecoTV 直接当作 OrionTV 的后端,播放记录与网页端同步

OrionTV 的成人内容过滤控制方式比较巧妙——用路径前缀区分:

  • https://你的域名/ → 家庭安全模式,自动过滤成人资源源和敏感关键词

  • https://你的域名/adult/ → 完整内容模式

原理是路径前缀会被自动重写,比如 /adult/api/search/api/search?adult=1,所以 OrionTV 端不需要任何额外配置。注意 URL 参数方式(?adult=1)只适用于 Web 端,OrionTV 不一定支持。

十二、升级、回滚与版本标签

DecoTV 的镜像标签策略很清晰,建议生产环境别用 latest

标签

说明

适用场景

latest

最新构建

想一直跟着走,含所有小更新

v1.0.0

固定版本号

生产环境,便于版本管理和回滚

v0.9.0

旧版本

出问题时的回滚目标

升级前必须知道这一条latest 时,重启容器不会自动拉取新镜像。 必须先手动 docker pull,再重建容器:

bash
docker compose pull
docker compose up -d
docker compose logs -f decotv-core

想要固定版本、支持回滚,就把 compose 里的镜像改成 ghcr.io/decohererk/decotv:v1.0.0。想全自动,可以上 watchtower,或者用 dockge / komodo 这类自带自动更新的 compose 面板。

补一句易被忽略的事:localstorage 模式无法迁移到数据库模式(数据在浏览器里,官方明确说不能直接迁)。真要迁移只能手动导出配置 JSON、部署新实例、再导入。所以如果你本来就打算长期用,一开始就选 Kvrocks,别先用 localstorage 试。

十三、排错清单

现象

原因与处理

docker pull 报 manifest 找不到

用的是旧镜像名。换成 ghcr.io/decohererk/decotv:latest

容器反复重启

数据库变量不匹配。检查 NEXT_PUBLIC_STORAGE_TYPE 与对应的 URL 变量是否配套;Kvrocks 端口是 6666 且前缀为 redis://

登录成功但操作提示 401

清 Cookie 重登;删掉多余的数据库变量;补上反代的 X-Forwarded-Proto

界面能开但搜不到片

正常——空壳项目,还没填 api_site 配置

改完配置不生效

先确认已保存;镜像没更新时先 docker pull 再重建,latest 重启不拉新镜像

播放中途断开、地址丢端口

反代用了 https://域名:非443端口 但没传带端口的 $http_host

拉取播放列表失败 (502)

上游 m3u8 源需要特定 Referer / Origin,换个源试试

FFmpeg API request failed (500/501)

环境缺 FFmpeg。官方 Docker 镜像已内置,自建镜像要确认 Dockerfile 包含它

转存下载 EACCES / permission denied

转存目录不可写。用具名卷,或 sudo chown -R 1001:1001 ./downloads 修正宿主机目录属主

转存大文件失败

检查磁盘空间、反代超时、FFMPEG_JOB_RETENTION_MS,必要时降低 FFMPEG_MAX_CONCURRENT_JOBS

关于下载功能,顺带说清楚两种模式的区别:「下载当前集」走浏览器分片下载,不依赖 FFmpeg,Web 部署基本都能用;「FFmpeg 转存下载」走服务端,官方 Docker 镜像已内置 ffmpeg / ffprobe,而 Vercel 这类 Serverless 环境跑不了长时间 FFmpeg 进程,会自动降级为浏览器分片下载。

十四、合规与安全:请认真读这一段

这部分我不替你做判断,只把该说的事实说清楚。

从技术上,官方给出的硬性建议是三条:设置强密码、不要公开分享你的实例链接、遵守当地法律法规。后台还有个 NEXT_PUBLIC_DISABLE_YELLOW_FILTER 可以关掉色情内容过滤,官方标注「不建议开启」——如果是有孩子的家庭环境,请保持默认的过滤开启状态。

从项目定位上,README 写得很明确:仅供学习和个人使用,请勿用于商业用途或公开服务;因公开分享导致的问题由用户自行承担。项目还特别声明其不在中国大陆地区提供服务,并希望不要在 B 站、小红书、微信公众号、抖音等平台发布内容宣传它。

所以这类自托管影音站的正确用法是:当作个人工具,不公开传播、不商用、不对外提供服务;播放源是你自己填的第三方地址,内容的合法性由你自行判断和承担。这不是免责套话——它直接决定了你这个实例能活多久。

写在最后

这次重写最重要的不是排版,而是三处纠正:镜像地址已经变了Cloudflare Pages + D1 方案已经没了部署完是个需要自己喂配置的空壳。旧教程里最花时间的部分(D1 建库、Pages 构建),在新版本里恰好是最没必要做的部分。

真正值得投入时间的地方在部署之后:选 Kvrocks 而不是 localstorage、把资源站配置整理成一份自己的 JSON、把 TMDB 和私人影库接上、以及给这台机器定好升级和备份的节奏。这些做完了,它才算是一个你会天天用的工具,而不是一个装完就忘的容器。

END