「续上篇」零压力搭建视频站!Ubuntu 服务器 + Cloudflare Pages 全自动 DASH 视频部署教程

摘要

本文介绍了一套利用 GitHub Actions 和 Cloudflare Pages 搭建的免费、全自动视频托管服务。作者分享了踩坑探索过程,详细讲解了系统工作原理、严格的目录结构、video.txt 写法及脚本配置。通过上传包含视频直链的文本文件,系统自动下载、转码并部署,生成可直接嵌入博客的 DASH 播放链接,全程无需服务器和数据库。

你是不是也遇到过这些问题:想在博客里放演示视频,却找不到稳定的外链;直接传大文件到 GitHub 又卡又受限;第三方平台广告多、链接不稳定、还没法自定义域名。

其实用 GitHub + GitHub Actions + Cloudflare Pages,就能搭一套完全属于自己、全自动运行的视频托管服务。不用服务器、不用数据库、全程免费,还能绑自己的子域名,拿来当博客专属视频源非常舒服。

一、我的踩坑探索之路(从崩溃到完美)

这套方案并不是一次就成功的,我走了很多弯路,踩了3个致命的坑,相信很多朋友都会遇到一模一样的问题,分享出来帮大家少走弯路。

坑1:服务器内存不足,Wrangler 直接崩溃

最开始,我尝试用 Ubuntu 服务器搭建,思路很简单:服务器转码、服务器上传,解放本地电脑。我按照教程安装了 FFmpeg、Node.js 和 Wrangler,结果一执行上传命令就报错,服务器直接卡死,查看日志发现是 ENOMEM: not enough memory(内存不足)。

我试过各种补救方法:给服务器加 SWAP 分区、限制 Node 内存、先打包视频再本地上传、分批次上传,但全都不稳定——要么卡死、要么超时、要么上传一半断掉。最终发现,低配服务器根本扛不住 Wrangler + FFmpeg 同时运行,这条路对新手、轻量用户来说太不友好,只能放弃。

坑2:GitHub 大文件限制,上传视频直接失败

放弃服务器方案后,我又想:直接把视频传到 GitHub 仓库,再用外链嵌入博客不就行了?结果一试才知道,GitHub 网页端单文件限制只有 25MB,而我博客里的演示视频、录屏,随便就超过这个大小,上传到一半就卡住、报错,甚至直接失败。

我尝试压缩视频,把 200MB 的视频压缩到 80MB,还是传不上去;又试了 Git LFS,不仅操作麻烦,还有额度限制,完全不适合免费博客使用。这时候我才意识到,直接传 MP4 到 GitHub 这条路,根本走不通。

坑3:链接配置错误,部署后无法播放

后来我灵光一现,想到“只传链接、让机器自己下载”的思路,但初期配置时还是踩了坑:要么 video.txt 里写了多个链接、加了注释,导致脚本读取失败,出现 网页解析失败 的报错;要么视频直链无效,出现 link fetch error(链接获取失败);还有一次部署成功后,播放地址报错 link dead(链接失效),排查后发现是文件夹命名有中文、视频直链不是可直接下载的格式。

最终灵光一现:GitHub Actions 一体化方案

踩了这么多坑后,我终于确定了核心思路:不用服务器、不用传大视频,只传一个几字节的文本文件,让 GitHub Actions 帮我完成所有“脏活”——下载视频、转码切片、过滤大文件、部署到 Cloudflare Pages。这套方案完美解决了所有问题,全程自动化,零手动干预,也不用占用本地和服务器内存。

下面,就开启正式的实操教程,跟着做,你就能快速用上这套全自动视频托管系统。

二、这套系统是怎么工作的?(先懂逻辑,再动手)

简单说就是三行逻辑,全程自动化,不用你手动干预:

  1. 你只在 GitHub 上放一个 文本文件(video.txt),里面只写视频的下载直链

  2. GitHub Actions 会自动触发,帮你完成:下载视频 → 转码切片 → 过滤大文件

  3. 自动部署到 Cloudflare Pages,生成可直接在博客里嵌入的播放外链

全程不用上传大视频、不用本地转码、不用手动处理文件,提交一次更改,剩下的全靠系统自动跑。

三、仓库目录结构(必须严格照这个来,错一步报错)

首先,你的 GitHub 仓库名称建议叫 my-videos(和后续脚本对应,也可以改,但脚本里要同步改),仓库内部结构必须固定如下,不能多一层、不能少一层:

plain
my-videos/  # 你的仓库根目录
└── videos/  # 视频存放的根目录(必须叫这个名字)
    ├── 视频文件夹1/  # 每个视频单独建一个文件夹
    │   └── video.txt  # 存放视频下载链接的文本文件(必须叫这个名字)
    └── 视频文件夹2/  # 第二个视频的文件夹
        └── video.txt  # 每个文件夹里只能有这一个文本文件

关键规则(重中之重,必看)

  • videos/ 是固定根目录,不能直接放视频、不能放其他文件,只能放子文件夹

  • 每个视频必须单独建一个文件夹,文件夹名称 只允许英文、数字、短横线 -(例:demo-01、video-123,不能叫“我的视频”)

  • 每个子文件夹里,必须有且只有一个文件,文件名固定为 video.txt(全小写、无空格,错一个字母都不行)

  • 所有文件夹名、文件名,绝对不能有中文、空格、特殊符号(比如:!、@、#、括号等)

四、video.txt 写法(最简单,却最容易出错)

video.txt 里不需要复杂内容,只有一个要求:一行内容,只放视频的下载直链,不要加任何多余的东西。这也是避免出现链接报错的关键。您可以把视频上传到自己的图床,下期会具体讲解如何用CF Pages+S3做免费图床。

正确示例(直接复制可用)

plain
https://xxx.com/demo-01.mp4

错误示例(绝对不能这样写,会报错)

plain
# 错误1:加了注释(会导致脚本读取失败,出现解析错误)
https://xxx.com/demo-01.mp4  # 这是我的视频

# 错误2:多换行(脚本只读取第一行,多余链接无用,还可能报错)
https://xxx.com/demo-01.mp4
https://xxx.com/other.mp4

# 错误3:加了多余文字(脚本无法识别链接,出现链接获取失败)
我的视频链接:https://xxx.com/demo-01.mp4

提示:视频链接必须是“直链”——就是点进去能直接下载 MP4 的链接,不能是网盘分享页、不能是需要登录才能看的链接,否则脚本会下载失败,出现 link fetch error

五、GitHub Actions 脚本(直接复制粘贴,不用改)

这是整套系统的核心,也是我最终定型的原版脚本,能实现“只处理新增/修改的视频,不重复转码、不浪费时间”,直接复制粘贴到指定路径即可,避免重复踩坑。

脚本路径(固定,不能改)

在你的 GitHub 仓库(my-videos)里,新建如下路径和文件:

plain
.github/workflows/deploy.yml

脚本完整代码(直接复制,粘贴到 deploy.yml 里)

YAML
name: 只处理新增/修改视频 · 下载+转码+部署CF Pages

on:
  push:
    branches: [ main ]  # 只在 main 分支提交时触发
  workflow_dispatch:  # 允许手动触发脚本

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest  # 用 Ubuntu 系统运行
    timeout-minutes: 60  # 超时时间60分钟,避免转码时超时

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2  # 必须开启,才能识别本次提交改动的文件

      - name: 安装工具 ffmpeg wget
        run: sudo apt update && sudo apt install -y ffmpeg wget  # 安装转码和下载工具

      - name: 安装 Cloudflare Wrangler
        run: npm install -g wrangler@latest  # 安装部署 CF Pages 的工具

      - name: 🔥 只处理本次提交的视频(核心步骤)
        run: |
          mkdir -p output  # 创建输出目录,存放转码后的文件
          # 获取本次提交新增/修改的 video.txt 文件
          CHANGED_FILES=$(git diff --name-only HEAD^ HEAD | grep -E "^videos/.*/video.txt$")
          
          # 如果没有改动任何 video.txt,直接退出,不浪费时间
          if [ -z "$CHANGED_FILES" ]; then
            echo "✅ 本次无改动,直接退出"
            exit 0
          fi

          # 循环处理每个改动的 video.txt
          for txt_file in $CHANGED_FILES; do
            echo "=================================================="
            echo "🎯 发现改动文件:$txt_file"
            
            # 获取视频文件夹路径(比如 videos/demo-01)
            VIDEO_DIR=$(dirname "$txt_file")
            # 获取视频文件夹名称(比如 demo-01)
            DIR_NAME=$(basename "$VIDEO_DIR")
            # 转码后的文件输出路径
            OUTPUT_DIR="output/$DIR_NAME"
            mkdir -p "$OUTPUT_DIR"  # 创建该视频的输出目录

            # 读取 video.txt 里的视频链接(只取第一行,去除空格和换行)
            VIDEO_URL=$(cat "$txt_file" | head -n 1 | tr -d '\r' | xargs)
            
            # 如果链接为空,跳过该文件
            if [ -z "$VIDEO_URL" ]; then
              echo "⚠️  该 video.txt 链接为空,跳过处理"
              continue
            fi

            # 下载视频,保存为 temp.mp4(临时文件,转码后删除)
            echo "📥 开始下载视频:$VIDEO_URL"
            wget -q -O temp.mp4 "$VIDEO_URL"  # -q 表示静默下载,不显示多余日志

            # 转码为 DASH 流媒体格式(适合网页播放,加载更快)
            echo "🎬 开始转码 DASH 格式"
            ffmpeg -i temp.mp4 \
              -map 0 -c:v libx264 -c:a aac \
              -f dash -seg_duration 4 \
              -use_template 1 -use_timeline 1 \
              "$OUTPUT_DIR/manifest.mpd"  # 转码后输出到 output 目录

            # 删除临时视频文件,节省空间
            rm -f temp.mp4
            echo "✅ 该视频处理完成"
          done

      - name: 🚫 删除 ≥25MB 的文件(避免 CF Pages 上传失败)
        run: find output -type f -size +24M -delete  # 过滤大于24MB的文件(留一点冗余)

      - name: ☁️ 部署到 Cloudflare Pages
        env:
          # 调用 GitHub 密钥(后续搭建教程会教怎么配置)
          CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
        run: |
          # 部署 output 目录到 CF Pages,--commit-dirty=true 消除警告
          wrangler pages deploy output/ --project-name="my-videos" --branch=main --commit-dirty=true

提示:脚本里的 --project-name="my-videos",要和你 GitHub 仓库的名称一致,如果你的仓库不叫 my-videos,这里要同步修改,否则会部署失败。另外,脚本中用到的 CLOUDFLARE_API_TOKENCLOUDFLARE_ACCOUNT_ID 两个环境变量,需要你提前在 GitHub 仓库配置好——分别填写你自己的 Cloudflare 账号 ID,以及手动开通的 Cloudflare API Token(开通时需勾选 Pages 相关权限),否则部署步骤会报错失败。相关获取方法见上期博客。

六、添加新视频的完整实操步骤(和我教你的一模一样)

配置好上面的内容后,以后你想给博客添加新视频,只需要这 5 步,全程网页操作,不用任何软件,也不会再踩之前的坑:

步骤1:进入 GitHub 仓库的 videos 目录

打开你的 GitHub 仓库(my-videos),点击顶部的 videos 文件夹,进入视频根目录。

步骤2:新建视频文件夹并创建 video.txt 文件

点击右上角的Add file → Create a new file,在文件名输入框里,输入你要建的视频文件夹名称 + 斜杠 / + video.txt(比如 demo-01/video.txt,全小写,不能改)。

步骤3:填写视频直链

在 video.txt 的编辑框里,只写一行视频直链(比如 https://xxx.com/demo-01.mp4),不要加任何多余内容,避免出现解析错误、链接失效等问题。

步骤4:提交更改,触发自动部署

拉到页面最下方,在 Commit new file 下方,填写提交说明(比如“添加 demo-01 视频”),然后点击 Commit new file,完成提交。

提交后会发生什么?

提交成功后,GitHub Actions 会自动触发,你可以点击仓库顶部的 Actions 标签,查看运行状态,会看到类似这样的日志(正常运行的标志):

plain
frame= 2674 fps= 36 q=28.0 size=N/A time=00:01:48.84 bitrate=N/A speed=1.45x    
frame= 2690 fps= 36 q=28.0 size=N/A time=00:01:49.48 bitrate=N/A speed=1.44x    
[dash @ 0x55e4f72972c0] Opening 'output/video-1/manifest.mpd.tmp' for writing
✨ Success! Uploaded 55 files (3.24 sec)
🌎 Deploying...
✨ Deployment complete! Take a peek over at https://7251ff58.my-videos.pages.dev

日志里出现 Deployment complete,就说明部署成功了。如果出现报错,可优先检查 video.txt 写法和文件夹命名是否符合要求。

七、最终播放地址 + 博客嵌入代码(直接复制用)

1. 播放地址格式(固定)

部署成功后,你的视频播放地址固定为:

plain
https://你的子域名/视频文件夹名/manifest.mpd

比如我自己绑定的子域名是 video.taiyanglee.eu.org,视频文件夹名是video-1,最终地址就是:

plain
https://video.taiyanglee.eu.org/video-1/manifest.mpd

提示:如果访问该地址出现link dead(链接失效),请检查视频直链是否有效、部署是否成功。

2. 博客嵌入代码(两种方式,任选其一)

### 方式:DASH 流媒体播放(推荐,加载快、适配性好)

HTML
<script src="https://cdn.dashjs.org/latest/dash.all.min.js"></script>
<video
  data-dashjs-player
  src="https://video.taiyanglee.eu.org/video-1/manifest.mpd"
  controls
  width="100%"
></video>
运行成功的样子⬆️,可见右侧在不断进行视频流获取,速度极快。
点击查看大图
运行成功的样子⬆️,可见右侧在不断进行视频流获取,速度极快。

八、常见报错解决办法(避坑必备)

结合我踩过的坑和常见报错,整理了4个高频问题的解决方法,遇到问题直接对照排查:

  • 报错 link fetch error:视频直链无效,检查直链是否能直接下载、是否需要登录,替换为有效的 MP4 直链。

  • 报错 网页解析失败:video.txt 写法错误,比如加了注释、多换行、有多余文字,修改为“一行仅一个直链”。

  • 报错 link dead:播放地址错误或部署失败,检查子域名绑定是否成功、视频文件夹名是否正确、部署日志是否有异常。

  • 部署卡住/超时:视频文件过大,建议控制在几百 MB 以内,避免转码时间过长。

九、下期预告

下一篇文章,我会从零开始,一步步带你用Cloudflare Pages+S2免费搭建你的图床:

全程复制粘贴,点点点就能完成,新手也能轻松搭出属于自己的视频图床。如果你也想摆脱第三方视频平台、拥有属于自己的稳定视频外链系统,记得来看下篇搭建教程。

正文结束
更新Cookie偏好设置